From 1e01ca303eb5dd55b5eb60b990964961a50da7b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 02:36:23 +0000 Subject: [PATCH 1/5] Initial plan From 55cf7150579b6e8b82c1de4a12e3392fadb6e418 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 03:06:33 +0000 Subject: [PATCH 2/5] add den and import-tree inputs to flake.nix, simplify outputs Agent-Logs-Url: https://github.com/auscyber/dotfiles/sessions/62de0edd-774b-4e16-9610-6910527cc340 Co-authored-by: auscyber <12080502+auscyber@users.noreply.github.com> --- flake.nix | 34 ++++------------------------------ 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/flake.nix b/flake.nix index 927913664..bc28d4e22 100644 --- a/flake.nix +++ b/flake.nix @@ -194,37 +194,11 @@ nixpkgs.follows = "unstable"; + den.url = "github:vic/den"; + import-tree.url = "github:vic/import-tree"; + }; - outputs = - inputs@{ - self, - flake-parts, - ... - }: - flake-parts.lib.mkFlake { inherit inputs; } ( - top@{ - config, - withSystem, - moduleWithSystem, - ... - }: - { - imports = [ - # Optional: use external flake logic, e.g. - # inputs.foo.flakeModules.default - ./flake - inputs.nix-topology.flakeModule - ]; - systems = [ - # systems for which you want to build the `perSystem` attributes - "aarch64-darwin" - "x86_64-linux" - "aarch64-linux" - # ... - ]; - - } - ); + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./flake); nixConfig = { extra-substituters = [ "https://nixos-raspberrypi.cachix.org" From 324873c4c83f417557d6003d3df68fe009e42295 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 03:11:20 +0000 Subject: [PATCH 3/5] transform flake to dendritic pattern using den + import-tree Agent-Logs-Url: https://github.com/auscyber/dotfiles/sessions/62de0edd-774b-4e16-9610-6910527cc340 Co-authored-by: auscyber <12080502+auscyber@users.noreply.github.com> --- flake.lock | 32 ++++++ flake/_dev/default.nix | 4 + flake/{dev => _dev}/flake.nix | 0 flake/{vendored => _vendored}/flake.nix | 0 flake/aspects/auscyber.nix | 16 +++ flake/aspects/auspc.nix | 15 +++ flake/aspects/defaults.nix | 114 +++++++++++++++++++++ flake/aspects/ivypierlot.nix | 16 +++ flake/aspects/ivys-macbook-pro.nix | 12 +++ flake/aspects/macmini.nix | 10 ++ flake/aspects/pentestvm.nix | 9 ++ flake/aspects/secondpc.nix | 12 +++ flake/aspects/standalone-homes.nix | 73 +++++++++++++ flake/aspects/surfacelaptop.nix | 12 +++ flake/aspects/wsl-nixos.nix | 10 ++ flake/default.nix | 70 +++++-------- flake/den.nix | 31 ++++++ flake/dev/default.nix | 4 - flake/homes.nix | 73 ++++++------- flake/systems.nix | 131 ++++-------------------- 20 files changed, 443 insertions(+), 201 deletions(-) create mode 100644 flake/_dev/default.nix rename flake/{dev => _dev}/flake.nix (100%) rename flake/{vendored => _vendored}/flake.nix (100%) create mode 100644 flake/aspects/auscyber.nix create mode 100644 flake/aspects/auspc.nix create mode 100644 flake/aspects/defaults.nix create mode 100644 flake/aspects/ivypierlot.nix create mode 100644 flake/aspects/ivys-macbook-pro.nix create mode 100644 flake/aspects/macmini.nix create mode 100644 flake/aspects/pentestvm.nix create mode 100644 flake/aspects/secondpc.nix create mode 100644 flake/aspects/standalone-homes.nix create mode 100644 flake/aspects/surfacelaptop.nix create mode 100644 flake/aspects/wsl-nixos.nix create mode 100644 flake/den.nix delete mode 100644 flake/dev/default.nix diff --git a/flake.lock b/flake.lock index 9c4906cbc..597575113 100644 --- a/flake.lock +++ b/flake.lock @@ -659,6 +659,21 @@ "type": "github" } }, + "den": { + "locked": { + "lastModified": 1774596030, + "narHash": "sha256-Gf24DeJaS0wttVoqYOiRPC3DrEKPeaQ5XYOXazzdLWA=", + "owner": "vic", + "repo": "den", + "rev": "91d41ed8b4a07e8b175ef2c9f8fc8470f0d75a41", + "type": "github" + }, + "original": { + "owner": "vic", + "repo": "den", + "type": "github" + } + }, "devenv": { "inputs": { "cachix": "cachix", @@ -3166,6 +3181,21 @@ "type": "github" } }, + "import-tree": { + "locked": { + "lastModified": 1771045967, + "narHash": "sha256-oYO4poyw0Sb/db2PigqugMlDwsvwLg6CSpFrMUWxA3Q=", + "owner": "vic", + "repo": "import-tree", + "rev": "c968d3b54d12cf5d9c13f16f7c545a06c9d1fde6", + "type": "github" + }, + "original": { + "owner": "vic", + "repo": "import-tree", + "type": "github" + } + }, "indexed": { "flake": false, "locked": { @@ -5364,6 +5394,7 @@ "darwin": "darwin_2", "deadlock": "deadlock", "deadlock-mod-manager": "deadlock-mod-manager", + "den": "den", "devenv": "devenv", "emacs": "emacs", "eww": "eww", @@ -5381,6 +5412,7 @@ "idris2": "idris2", "idris2-pkgs": "idris2-pkgs", "impermanence": "impermanence", + "import-tree": "import-tree", "input-branches": "input-branches", "input-leap": "input-leap", "kmonad": "kmonad", diff --git a/flake/_dev/default.nix b/flake/_dev/default.nix new file mode 100644 index 000000000..f0cb62c67 --- /dev/null +++ b/flake/_dev/default.nix @@ -0,0 +1,4 @@ +{ inputs, ... }: +{ + +} diff --git a/flake/dev/flake.nix b/flake/_dev/flake.nix similarity index 100% rename from flake/dev/flake.nix rename to flake/_dev/flake.nix diff --git a/flake/vendored/flake.nix b/flake/_vendored/flake.nix similarity index 100% rename from flake/vendored/flake.nix rename to flake/_vendored/flake.nix diff --git a/flake/aspects/auscyber.nix b/flake/aspects/auscyber.nix new file mode 100644 index 000000000..48c3ce804 --- /dev/null +++ b/flake/aspects/auscyber.nix @@ -0,0 +1,16 @@ +{ ... }: +{ + den.aspects.auscyber = { + # Base home-manager configuration shared across all hosts where auscyber + # lives. Per-host additions are delivered by each host's provides.auscyber + # (see e.g. flake/aspects/auspc.nix). + homeManager = + { pkgs, ... }: + { + home = { + username = "auscyber"; + homeDirectory = "/home/auscyber"; + }; + }; + }; +} diff --git a/flake/aspects/auspc.nix b/flake/aspects/auspc.nix new file mode 100644 index 000000000..b4e0a8be0 --- /dev/null +++ b/flake/aspects/auspc.nix @@ -0,0 +1,15 @@ +{ ... }: +{ + den.aspects.auspc = { + # NixOS configuration for the auspc host. + nixos = { ... }: { + imports = [ ../../systems/x86_64-linux/auspc ]; + }; + + # Per-host home-manager additions for auscyber on auspc, delivered via + # the mutual-provider battery (host.provides.user). + provides.auscyber = { ... }: { + homeManager.imports = [ (../../homes/x86_64-linux + "/auscyber@auspc") ]; + }; + }; +} diff --git a/flake/aspects/defaults.nix b/flake/aspects/defaults.nix new file mode 100644 index 000000000..e243ecc24 --- /dev/null +++ b/flake/aspects/defaults.nix @@ -0,0 +1,114 @@ +{ + config, + inputs, + # Enable syntax for den battery references. + __findFile ? __findFile, + den, + ... +}: +{ + # ── NixOS defaults ────────────────────────────────────────────────────────── + den.default.nixos = { + imports = [ + inputs.stylix.nixosModules.stylix + inputs.arion.nixosModules.arion + inputs.lanzaboote.nixosModules.lanzaboote + inputs.impermanence.nixosModules.impermanence + inputs.home-manager.nixosModules.home-manager + inputs.nixos-wsl.nixosModules.default + inputs.agenix.nixosModules.default + inputs.agenix-rekey.nixosModules.default + inputs.sops-nix.nixosModules.sops + inputs.attic.nixosModules.atticd + ../../modules/common/vpn.nix + ../../modules/common/builders + ../../modules/common/secrets.nix + ../../modules/common/nix + ../../modules/common/common + ../../modules/common/allConfigs.nix + ../../modules/common/hm + ../../modules/common/ssh-keys.nix + ../../modules/nixos/bootlogo + ../../modules/nixos/builders + ../../modules/nixos/games + ../../modules/nixos/general + ../../modules/nixos/secrets + ../../modules/nixos/ssh + ]; + nixpkgs.config.allowUnfree = true; + nixpkgs.overlays = builtins.attrValues inputs.self.overlays; + auscybernix.secrets.enable = true; + }; + + # ── Darwin defaults ───────────────────────────────────────────────────────── + den.default.darwin = { + imports = [ + inputs.stylix.darwinModules.stylix + inputs.nix-homebrew.darwinModules.nix-homebrew + inputs.home-manager.darwinModules.home-manager + inputs.sops-nix.darwinModules.sops + inputs.agenix.darwinModules.default + inputs.agenix-rekey.nixosModules.default + ../../modules/common/builders + ../../modules/common/vpn.nix + ../../modules/common/nix + ../../modules/common/secrets.nix + ../../modules/common/hm + ../../modules/common/common + ../../modules/common/allConfigs.nix + ../../modules/common/kmonad + ../../modules/common/ssh-keys.nix + ../../modules/darwin/builders + ../../modules/darwin/finder + ../../modules/darwin/general + ../../modules/darwin/hmApps + ../../modules/darwin/homebrew + ../../modules/darwin/keys + ../../modules/darwin/network + ]; + nixpkgs.config.allowUnfree = true; + nixpkgs.overlays = builtins.attrValues inputs.self.overlays; + auscybernix.secrets.enable = true; + }; + + # ── Home-manager defaults (all managed users on all hosts) ────────────────── + den.default.homeManager = { + imports = [ + inputs._1password-shell-plugins.hmModules.default + inputs.zen-browser.homeModules.default + inputs.nixvim.homeModules.default + inputs.nix-index-database.homeModules.nix-index + inputs.sops-nix.homeManagerModules.sops + inputs.agenix.homeManagerModules.default + inputs.agenix-rekey.homeManagerModules.default + inputs.vscode-server.homeModules.default + inputs.niri.homeModules.niri + ../../modules/common/secrets.nix + ../../modules/common/nix + ../../modules/common/allConfigs.nix + ]; + auscybernix.secrets.enable = true; + }; + + # ── Standalone home extras (den.homes.*) ──────────────────────────────────── + den.schema.home.imports = [ + inputs.stylix.homeModules.stylix + ]; + + # ── State-version defaults ────────────────────────────────────────────────── + den.default = { + nixos.system.stateVersion = "25.05"; + darwin.system.stateVersion = 6; + homeManager.home.stateVersion = "25.05"; + }; + + # ── Den batteries ─────────────────────────────────────────────────────────── + # mutual-provider: enables ${host}.provides.${user} and ${user}.provides.${host} + # hostname: automatically sets networking.hostName + # define-user: automatically creates users.users. on each host + den.default.includes = [ + + + + ]; +} diff --git a/flake/aspects/ivypierlot.nix b/flake/aspects/ivypierlot.nix new file mode 100644 index 000000000..be023f3bc --- /dev/null +++ b/flake/aspects/ivypierlot.nix @@ -0,0 +1,16 @@ +{ ... }: +{ + den.aspects.ivypierlot = { + # Base home-manager configuration shared across all hosts where ivypierlot + # lives. Per-host additions are delivered by each host's provides.ivypierlot + # (see e.g. flake/aspects/ivys-macbook-pro.nix). + homeManager = + { pkgs, ... }: + { + home = { + username = "ivypierlot"; + homeDirectory = "/Users/ivypierlot"; + }; + }; + }; +} diff --git a/flake/aspects/ivys-macbook-pro.nix b/flake/aspects/ivys-macbook-pro.nix new file mode 100644 index 000000000..881c34b82 --- /dev/null +++ b/flake/aspects/ivys-macbook-pro.nix @@ -0,0 +1,12 @@ +{ ... }: +{ + den.aspects."Ivys-MacBook-Pro" = { + darwin = { ... }: { + imports = [ ../../systems/aarch64-darwin/Ivys-MacBook-Pro ]; + }; + + provides.ivypierlot = { ... }: { + homeManager.imports = [ (../../homes/aarch64-darwin + "/ivypierlot@Ivys-MacBook-Pro") ]; + }; + }; +} diff --git a/flake/aspects/macmini.nix b/flake/aspects/macmini.nix new file mode 100644 index 000000000..8d282e138 --- /dev/null +++ b/flake/aspects/macmini.nix @@ -0,0 +1,10 @@ +{ ... }: +{ + den.aspects.macmini = { + darwin = { ... }: { + imports = [ ../../systems/aarch64-darwin/macmini ]; + }; + # No dedicated home configuration for macmini; ivypierlot's base + # homeManager aspect applies via den.aspects.ivypierlot.homeManager. + }; +} diff --git a/flake/aspects/pentestvm.nix b/flake/aspects/pentestvm.nix new file mode 100644 index 000000000..663496252 --- /dev/null +++ b/flake/aspects/pentestvm.nix @@ -0,0 +1,9 @@ +{ ... }: +{ + den.aspects.pentestvm = { + nixos = { ... }: { + imports = [ ../../systems/x86_64-linux/pentestvm ]; + }; + # No home configuration exists for pentestvm. + }; +} diff --git a/flake/aspects/secondpc.nix b/flake/aspects/secondpc.nix new file mode 100644 index 000000000..223d77dd2 --- /dev/null +++ b/flake/aspects/secondpc.nix @@ -0,0 +1,12 @@ +{ ... }: +{ + den.aspects.secondpc = { + nixos = { ... }: { + imports = [ ../../systems/x86_64-linux/secondpc ]; + }; + + provides.auscyber = { ... }: { + homeManager.imports = [ (../../homes/x86_64-linux + "/auscyber@secondpc") ]; + }; + }; +} diff --git a/flake/aspects/standalone-homes.nix b/flake/aspects/standalone-homes.nix new file mode 100644 index 000000000..fee4cca12 --- /dev/null +++ b/flake/aspects/standalone-homes.nix @@ -0,0 +1,73 @@ +{ ... }: +let + linuxHome = username: { + homeManager = + { pkgs, ... }: + { + home = { + inherit username; + homeDirectory = "/home/${username}"; + }; + auscybernix.standalone.enable = true; + }; + }; +in +{ + # Standalone home configurations for machines that are NOT managed by NixOS + # or nix-darwin in this flake (e.g. foreign distros, remote VMs, shared + # machines). These correspond to the den.homes.* entries in flake/den.nix. + # Per-host path imports are inlined here because each home is unique to a + # single (user, host) combination with no shared host aspect. + + den.aspects."auscyber@arch" = (linuxHome "auscyber") // { + homeManager = + { pkgs, ... }: + { + imports = [ (../../homes/x86_64-linux + "/auscyber@arch") ]; + home = { + username = "auscyber"; + homeDirectory = "/home/auscyber"; + }; + auscybernix.standalone.enable = true; + }; + }; + + den.aspects."auscyber@laptop" = { + homeManager = + { pkgs, ... }: + { + imports = [ (../../homes/x86_64-linux + "/auscyber@laptop") ]; + home = { + username = "auscyber"; + homeDirectory = "/home/auscyber"; + }; + auscybernix.standalone.enable = true; + }; + }; + + den.aspects."ivy@imflopet" = { + homeManager = + { pkgs, ... }: + { + imports = [ (../../homes/x86_64-linux + "/ivy@imflopet") ]; + home = { + username = "ivy"; + homeDirectory = "/home/ivy"; + }; + auscybernix.standalone.enable = true; + }; + }; + + den.aspects."ivy@vmi1472413.contaboserver.net" = { + homeManager = + { pkgs, ... }: + { + imports = [ (../../homes/x86_64-linux + "/ivy@vmi1472413.contaboserver.net") ]; + home = { + username = "ivy"; + homeDirectory = "/home/ivy"; + }; + auscybernix.standalone.enable = true; + }; + }; +} diff --git a/flake/aspects/surfacelaptop.nix b/flake/aspects/surfacelaptop.nix new file mode 100644 index 000000000..024a18b19 --- /dev/null +++ b/flake/aspects/surfacelaptop.nix @@ -0,0 +1,12 @@ +{ ... }: +{ + den.aspects.surfacelaptop = { + nixos = { ... }: { + imports = [ ../../systems/x86_64-linux/surfacelaptop ]; + }; + + provides.auscyber = { ... }: { + homeManager.imports = [ (../../homes/x86_64-linux + "/auscyber@surfacelaptop") ]; + }; + }; +} diff --git a/flake/aspects/wsl-nixos.nix b/flake/aspects/wsl-nixos.nix new file mode 100644 index 000000000..4a05200a4 --- /dev/null +++ b/flake/aspects/wsl-nixos.nix @@ -0,0 +1,10 @@ +{ ... }: +{ + den.aspects.wsl-nixos = { + nixos = { ... }: { + imports = [ ../../systems/x86_64-linux/wsl-nixos ]; + }; + # No dedicated home configuration for wsl-nixos; auscyber's base + # homeManager aspect applies via den.aspects.auscyber.homeManager. + }; +} diff --git a/flake/default.nix b/flake/default.nix index 6d5c3880a..e1de1303f 100644 --- a/flake/default.nix +++ b/flake/default.nix @@ -1,61 +1,43 @@ +{ inputs, ... }: { - self, - inputs, - lib, - ... -}: -{ + # External flake modules and out-of-tree directories that import-tree + # cannot auto-discover. All *.nix files inside ./flake/ (except those + # under _-prefixed paths) are picked up automatically by import-tree. imports = [ - inputs.agenix-rekey.flakeModule - ./systems.nix + inputs.nix-topology.flakeModule + inputs.flake-parts.flakeModules.partitions + inputs.flake-parts.flakeModules.flakeModules + inputs.input-branches.flakeModules.default ../lib ../docs ../overlays - ./homes.nix - ./apps.nix - ./vpn.nix - - ./secrets.nix - ./shells.nix ../ci - ./packages.nix - ./input-branches.nix - inputs.flake-parts.flakeModules.partitions - inputs.flake-parts.flakeModules.flakeModules - inputs.input-branches.flakeModules.default - ./formatter.nix - ./templates.nix - ./builders.nix ]; - flake = { - }; perSystem = - { config, pkgs, ... }: + { pkgs, ... }: { apps.initHome = { type = "app"; program = pkgs.writeShellScriptBin "init-home" '' - instance_folder="./homes/${pkgs.stdenv.system}/$USER@$(hostname -s)" - if ! [ -d "$instance_folder" ]; then - echo "Creating home instance folder at $instance_folder" - else - echo "Home instance folder $instance_folder already exists" - exit 1 - fi - echo "Creating default.nix in $instance_folder" - mkdir -p "$instance_folder" - cat << EOF > "$instance_folder/default.nix" - {config, pkgs,...}: - { - auscybernix.nix.flake = "$CWD"; - home.stateVersion = "24.05"; - } - EOF - ''; + instance_folder="./homes/${pkgs.stdenv.system}/$USER@$(hostname -s)" + if ! [ -d "$instance_folder" ]; then + echo "Creating home instance folder at $instance_folder" + else + echo "Home instance folder $instance_folder already exists" + exit 1 + fi + echo "Creating default.nix in $instance_folder" + mkdir -p "$instance_folder" + cat << EOF > "$instance_folder/default.nix" + {config, pkgs,...}: + { + auscybernix.nix.flake = "$CWD"; + home.stateVersion = "24.05"; + } + EOF + ''; }; - }; - } diff --git a/flake/den.nix b/flake/den.nix new file mode 100644 index 000000000..99dfdb898 --- /dev/null +++ b/flake/den.nix @@ -0,0 +1,31 @@ +{ inputs, lib, ... }: +{ + # Import den's dendritic flake module which wires up den's own module tree + # into the flake-parts evaluation and exposes den.hosts, den.homes, + # den.aspects, den.schema, den.default, etc. as flake-parts options. + imports = [ + (inputs.den.flakeModules.dendritic or { }) + ]; + + # ── NixOS hosts ──────────────────────────────────────────────────────────── + den.hosts.x86_64-linux.auspc.users.auscyber = { }; + den.hosts.x86_64-linux.pentestvm.users.auscyber = { }; + den.hosts.x86_64-linux.secondpc.users.auscyber = { }; + den.hosts.x86_64-linux.surfacelaptop.users.auscyber = { }; + den.hosts.x86_64-linux.wsl-nixos.users.auscyber = { }; + + # ── Darwin hosts ─────────────────────────────────────────────────────────── + den.hosts.aarch64-darwin."Ivys-MacBook-Pro".users.ivypierlot = { }; + den.hosts.aarch64-darwin.macmini.users.ivypierlot = { }; + + # ── Standalone home configurations ───────────────────────────────────────── + # These are home-manager configs for machines NOT in systems/ (e.g. managed + # by another distro, a remote server, or a shared machine). + den.homes.x86_64-linux."auscyber@arch" = { }; + den.homes.x86_64-linux."auscyber@laptop" = { }; + den.homes.x86_64-linux."ivy@imflopet" = { }; + den.homes.x86_64-linux."ivy@vmi1472413.contaboserver.net" = { }; + + # Build standalone homeConfigurations for all users on all hosts. + den.schema.user.classes = lib.mkDefault [ "homeManager" ]; +} diff --git a/flake/dev/default.nix b/flake/dev/default.nix deleted file mode 100644 index fe0a88a8e..000000000 --- a/flake/dev/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ input, ... }: -{ - -} diff --git a/flake/homes.nix b/flake/homes.nix index 4b41cf382..62a20bd62 100644 --- a/flake/homes.nix +++ b/flake/homes.nix @@ -1,61 +1,48 @@ { - inputs, self, + inputs, lib, ... }: let inherit (self.lib.file) parseHomeConfigurations; - - homesPath = ../homes; - allHomes = parseHomeConfigurations homesPath; - - generateHomeConfiguration = - name: - { - system, - username, - userAtHost, - hostname, - path, - ... - }: - { - name = userAtHost; # Use the full "username@hostname" as key - value = self.lib.system.mkHome { - inherit - inputs - hostname - username - ; - system = lib.strings.removeSuffix "-rpi" system; # Strip -rpi suffix for rpi homes - modules = [ path ]; - }; - }; + # Only the Raspberry Pi home is built as a standalone homeConfiguration + # here. All other hosts/users are handled by den (flake/den.nix) which + # creates both NixOS-embedded and standalone homeConfigurations via its + # homeManager user class. + rpiHomes = lib.filterAttrs ( + _: { system, ... }: lib.hasSuffix "rpi" system + ) (parseHomeConfigurations ../homes); in { - imports = [ inputs.home-manager.flakeModules.home-manager ]; - flake = { homeModules = rec { default = ../modules/home; recursive = { - imports = lib.importModulesRecursive ../modules/home ++ lib.externalHmModules ++ [ default ]; - + imports = [ default ] ++ self.lib.file.importModulesRecursive ../modules/home; }; }; - # Dynamically generated home configurations - homeConfigurations = lib.mapAttrs' generateHomeConfiguration allHomes; + # Standalone home configurations for Raspberry Pi users (non-standard + # builder — kept outside den). + homeConfigurations = lib.mapAttrs' ( + _: + { + system, + username, + userAtHost, + hostname, + path, + ... + }: + { + name = userAtHost; + value = self.lib.system.mkHome { + inherit inputs hostname username; + system = lib.strings.removeSuffix "-rpi" system; + modules = [ path ]; + }; + } + ) rpiHomes; }; - perSystem = - { - config, - system, - pkgs, - ... - }: - { - - }; } diff --git a/flake/systems.nix b/flake/systems.nix index 063f19ef0..8af4fcec4 100644 --- a/flake/systems.nix +++ b/flake/systems.nix @@ -1,119 +1,30 @@ { - config, - inputs, self, + inputs, lib, ... }: let - overlay = config.overlays.default; - inherit (self.lib.file) - parseSystemConfigurations - filterNixOSSystems - filterDarwinSystems - filterRpiSystems - ; - inherit (inputs.nixpkgs.lib) - hasSuffix - ; - systemsPath = ../systems; - allSystems = parseSystemConfigurations systemsPath; + inherit (self.lib.file) parseSystemConfigurations filterRpiSystems; + allSystems = parseSystemConfigurations ../systems; in { - flake = { - auscybernix = rec { - containerModules = importedNixosModules ++ self.lib.importModulesRecursive ../modules/nixos; - - importedHomeModules = [ - inputs._1password-shell-plugins.hmModules.default - inputs.zen-browser.homeModules.default - inputs.nixvim.homeModules.default - inputs.nix-index-database.homeModules.nix-index - inputs.sops-nix.homeManagerModules.sops - inputs.agenix.homeManagerModules.default - inputs.agenix-rekey.homeManagerModules.default - inputs.vscode-server.homeModules.default - - inputs.niri.homeModules.niri - ]; - standaloneHomeModules = [ -# inputs.niri.homeModules.default - inputs.stylix.homeModules.stylix - ]; - importedNixosModules = [ - ../modules/common/vpn.nix - ../modules/common/builders - ../modules/common/secrets.nix - ../modules/common/nix - ../modules/common/common - -# ../modules/common/builders/builder.nix - inputs.stylix.nixosModules.stylix - inputs.arion.nixosModules.arion - inputs.lanzaboote.nixosModules.lanzaboote - inputs.impermanence.nixosModules.impermanence - inputs.home-manager.nixosModules.home-manager - inputs.nixos-wsl.nixosModules.default - inputs.agenix.nixosModules.default - inputs.agenix-rekey.nixosModules.default - inputs.sops-nix.nixosModules.sops - inputs.attic.nixosModules.atticd - - ]; - importedDarwinModules = [ - -# ../modules/common/builders/builder.nix - ../modules/common/builders - ../modules/common/vpn.nix - inputs.stylix.darwinModules.stylix - inputs.nix-homebrew.darwinModules.nix-homebrew - inputs.home-manager.darwinModules.home-manager - inputs.sops-nix.darwinModules.sops - inputs.agenix.darwinModules.default - inputs.agenix-rekey.nixosModules.default - - ]; - }; - - nixosConfigurations = lib.mapAttrs' ( - name: - { system, hostname, ... }: - { - name = hostname; - value = - if hasSuffix "rpi" system then - self.lib.system.rpi.mkSystem { - inherit inputs system hostname; - } - else - - self.lib.system.mkNixos { - inherit inputs system hostname; - }; - } - ) (filterNixOSSystems allSystems); - - darwinConfigurations = lib.mapAttrs' ( - name: - { system, hostname, ... }: - { - name = hostname; - value = self.lib.system.mkDarwin { - inherit inputs system hostname; - username = "IvyPierlot"; - }; - } - ) (filterDarwinSystems allSystems); - installImages = lib.mapAttrs' ( - name: - { system, hostname, ... }: - { - name = hostname; - value = - (self.lib.system.rpi.mkInstaller { - inherit inputs system hostname; - }).config.system.build.sdImage; - } - ) (filterRpiSystems allSystems); - }; + # Architectures that flake-parts builds perSystem attributes for. + systems = [ + "aarch64-darwin" + "x86_64-linux" + "aarch64-linux" + ]; + + # Raspberry Pi SD-card installer images. NixOS/darwin hosts are now + # declared in flake/den.nix and built by den; only the non-standard RPi + # installer flow stays here. + flake.installImages = lib.mapAttrs' ( + name: + { system, hostname, ... }: + { + name = hostname; + value = (self.lib.system.rpi.mkInstaller { inherit inputs system hostname; }).config.system.build.sdImage; + } + ) (filterRpiSystems allSystems); } From 9f4af39fd1756b44348fc1634e5890d3a028477d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 04:02:48 +0000 Subject: [PATCH 4/5] Changes before error encountered Agent-Logs-Url: https://github.com/auscyber/dotfiles/sessions/082a6975-8a10-4710-a0b3-39afc6da0df8 Co-authored-by: auscyber <12080502+auscyber@users.noreply.github.com> --- flake/aspects/bootlogo.nix | 18 ++ flake/aspects/browsers.nix | 143 ++++++++++++++++ flake/aspects/builders.nix | 95 +++++++++++ flake/aspects/editors.nix | 137 ++++++++++++++++ flake/aspects/gaming.nix | 69 ++++++++ flake/aspects/gpg.nix | 32 ++++ flake/aspects/keybinds.nix | 226 +++++++++++++++++++++++++ flake/aspects/languages.nix | 41 +++++ flake/aspects/media.nix | 62 +++++++ flake/aspects/shell.nix | 202 +++++++++++++++++++++++ flake/aspects/ssh.nix | 63 +++++++ flake/aspects/terminal.nix | 49 ++++++ flake/aspects/vpn.nix | 79 +++++++++ flake/aspects/wm-darwin.nix | 317 ++++++++++++++++++++++++++++++++++++ flake/aspects/wm-linux.nix | 169 +++++++++++++++++++ 15 files changed, 1702 insertions(+) create mode 100644 flake/aspects/bootlogo.nix create mode 100644 flake/aspects/browsers.nix create mode 100644 flake/aspects/builders.nix create mode 100644 flake/aspects/editors.nix create mode 100644 flake/aspects/gaming.nix create mode 100644 flake/aspects/gpg.nix create mode 100644 flake/aspects/keybinds.nix create mode 100644 flake/aspects/languages.nix create mode 100644 flake/aspects/media.nix create mode 100644 flake/aspects/shell.nix create mode 100644 flake/aspects/ssh.nix create mode 100644 flake/aspects/terminal.nix create mode 100644 flake/aspects/vpn.nix create mode 100644 flake/aspects/wm-darwin.nix create mode 100644 flake/aspects/wm-linux.nix diff --git a/flake/aspects/bootlogo.nix b/flake/aspects/bootlogo.nix new file mode 100644 index 000000000..e79a22866 --- /dev/null +++ b/flake/aspects/bootlogo.nix @@ -0,0 +1,18 @@ +{ den, ... }: +{ + # ── Boot logo aspect ────────────────────────────────────────────────────────── + # NixOS: Plymouth boot splash screen. + # Include in a host aspect to enable a graphical boot screen. + den.aspects.bootlogo = { + nixos = + { config, lib, ... }: + { + options.auscybernix.bootlogo.enable = + lib.mkEnableOption "AusCyberNix plymouth boot logo"; + + config = lib.mkIf config.auscybernix.bootlogo.enable { + boot.plymouth.enable = true; + }; + }; + }; +} diff --git a/flake/aspects/browsers.nix b/flake/aspects/browsers.nix new file mode 100644 index 000000000..5ed483dd8 --- /dev/null +++ b/flake/aspects/browsers.nix @@ -0,0 +1,143 @@ +{ den, ... }: +{ + # ── Browsers aspect ─────────────────────────────────────────────────────────── + # Home-manager: Zen browser (privacy-focused Firefox fork), Helium browser. + # Include in a user aspect; enable individual browsers via option flags. + den.aspects.browsers = { + homeManager = + { config, lib, pkgs, ... }: + let + cfgZen = config.auscybernix.browsers.zen-browser; + cfgHelium = config.auscybernix.browsers.helium; + stdenv = pkgs.stdenv; + policies = { + DisableAppUpdate = true; + DisableTelemetry = true; + }; + in + { + options.auscybernix.browsers.zen-browser = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Zen Browser."; + }; + profileName = lib.mkOption { + type = lib.types.str; + default = "ivy (Default)"; + description = "Name of the default Zen Browser profile."; + }; + }; + options.auscybernix.browsers.helium.enable = + lib.mkEnableOption "Helium browser"; + + config = lib.mkMerge [ + # ── Zen browser ────────────────────────────────────────────────── + (lib.mkIf cfgZen.enable { + stylix.targets.zen-browser.profileNames = [ cfgZen.profileName ]; + programs.zen-browser = { + enable = true; + nativeMessagingHosts = [ pkgs._1password-gui-beta ]; + darwinDefaultsId = "app.zen-browser.zen"; + package = lib.mkForce ( + if stdenv.isDarwin then + null + else + pkgs.wrapFirefox + (pkgs.zen-browser.override { inherit policies; }) + { + extraPrefs = config.programs.zen-browser.extraPrefs; + extraPrefsFiles = config.programs.zen-browser.extraPrefsFiles; + nativeMessagingHosts = config.programs.zen-browser.nativeMessagingHosts; + } + ); + inherit policies; + profiles."${cfgZen.profileName}" = { + search = { + force = true; + engines = { + kagi = { + name = "Kagi Search"; + urls = [ { template = "https://kagi.com/search"; params = [ { name = "q"; value = "{searchTerms}"; } ]; } ]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/kagi-search.svg"; + definedAliases = [ "@kagi" ]; + }; + nix-packages = { + name = "Nix Packages"; + urls = [ { template = "https://search.nixos.org/packages"; params = [ { name = "type"; value = "packages"; } { name = "query"; value = "{searchTerms}"; } ]; } ]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@np" ]; + }; + unduck = { + name = "UnDuck"; + urls = [ { template = "https://unduck.link"; params = [ { name = "q"; value = "{searchTerms}"; } ]; } ]; + }; + scholar = { + name = "Google Scholar"; + urls = [ { template = "https://scholar.google.com/scholar"; params = [ { name = "q"; value = "{searchTerms}"; } ]; } ]; + definedAliases = [ "@sch" ]; + }; + "Home-Manager-Options" = { + urls = [ { template = "https://home-manager-options.extranix.com"; params = [ { name = "query"; value = "{searchTerms}"; } { name = "release"; value = "master"; } ]; } ]; + definedAliases = [ "@hm" ]; + }; + }; + default = "kagi"; + privateDefault = "kagi"; + }; + isDefault = true; + settings = { + "extensions.autoDisableScopes" = 0; + "zen.welcome-screen.seen" = true; + }; + containers = { + Queer = { id = 3; color = "pink"; }; + Uni = { color = "green"; icon = "fruit"; id = 2; }; + Shopping = { color = "blue"; icon = "cart"; id = 1; }; + }; + extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [ + auto-tab-discard + libkey-nomad + onepassword-password-manager + zotero-connector + kagi-search + ublock-origin + ]; + }; + }; + home.activation = lib.optionalAttrs stdenv.hostPlatform.isDarwin { + zen-browser = + let + profiles-ini = + if stdenv.hostPlatform.isLinux then + "${config.xdg.configHome}/zen/profiles.ini" + else + "${config.home.homeDirectory}/Library/\"Application Support\"/zen/profiles.ini"; + in + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + rm ${profiles-ini}.backup + mv ${profiles-ini} ${profiles-ini}.generate + cat ${profiles-ini}.generate > ${profiles-ini} + echo ZenAvatarPath=chrome://browser/content/zen-avatars/avatar-01.svg >> ${profiles-ini} + ''; + }; + }) + + # ── Helium ──────────────────────────────────────────────────────── + (lib.mkIf cfgHelium.enable { + home.packages = with pkgs; [ helium ]; + programs.helium = { + enable = true; + extensions = [ + { id = "cdglnehniifkbagbbombnjghhcihifij"; } + { id = "aeblfdkhhhdcdjpifhhbdiojplfjncoa"; } # 1Password + { id = "ekhagklcjbdpajgpjgmbionohlpdbjgc"; } # Zotero + { id = "lkoeejijapdihgbegpljiehpnlkadljb"; } # libKey nomad + { id = "hghakoefmnkhamdhenpbogkeopjlkpoa"; } # Lean library + ]; + }; + }) + ]; + }; + }; +} diff --git a/flake/aspects/builders.nix b/flake/aspects/builders.nix new file mode 100644 index 000000000..ee69e739c --- /dev/null +++ b/flake/aspects/builders.nix @@ -0,0 +1,95 @@ +{ den, ... }: +{ + # ── Builders aspect ─────────────────────────────────────────────────────────── + # Distributed Nix builds: declares the shared options (from modules/common/builders), + # then adds platform-specific nix.buildMachines configuration for NixOS and Darwin. + # Include in host aspects that participate in distributed builds. + den.aspects.builders = { + nixos = + { + config, + lib, + pkgs, + flakeConfig, + system, + systemIdentifier, + ... + }: + let + cfg = config.auscybernix.nix.builders; + in + { + # Re-use the shared option declarations + common config (age key gen, + # nix.distributedBuilds, builder user setup). + imports = [ ../../modules/common/builders ]; + + config = lib.mkIf cfg.enable { + nix.buildMachines = + lib.flip lib.mapAttrsToList + (lib.filterAttrs + (name: x: + name != systemIdentifier + && (cfg.absoluteSpeedFactor * 0.75) > x.absoluteSpeedFactor) + flakeConfig.flake.auscybernix.builders.buildMachines) + (name: builder: { + protocol = "ssh-ng"; + hostName = builder.ipAddress; + systems = builder.systems; + publicHostKey = builder.publicHostKey; + maxJobs = builder.maxJobs; + speedFactor = builder.absoluteSpeedFactor / cfg.absoluteSpeedFactor; + supportedFeatures = builder.features; + sshUser = builder.username; + sshKey = config.age.secrets."builder-ssh-key".path; + }); + }; + }; + + darwin = + { + config, + lib, + pkgs, + flakeConfig, + system, + systemIdentifier, + ... + }: + let + cfg = config.auscybernix.nix.builders; + in + { + imports = [ ../../modules/common/builders ]; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + nix.buildMachines = + lib.flip lib.mapAttrsToList + (lib.filterAttrs + (name: x: + name != systemIdentifier + && cfg.absoluteSpeedFactor > x.absoluteSpeedFactor) + flakeConfig.flake.auscybernix.builders.buildMachines) + (name: builder: { + protocol = "ssh-ng"; + hostName = builder.ipAddress; + systems = builder.systems; + maxJobs = builder.maxJobs; + speedFactor = builder.speedFactor / cfg.absoluteSpeedFactor; + publicHostKey = builder.publicHostKey; + supportedFeatures = builder.features; + sshUser = builder.username; + sshKey = config.age.secrets."builder-ssh-key".path; + }); + } + (lib.mkIf cfg.builderConfig.enable { + users.knownUsers = [ cfg.builderConfig.builderUser ]; + users.groups."com.apple.access_ssh".members = [ cfg.builderConfig.builderUser ]; + users.users."${cfg.builderConfig.builderUser}".uid = 3000; + }) + ] + ); + }; + }; +} diff --git a/flake/aspects/editors.nix b/flake/aspects/editors.nix new file mode 100644 index 000000000..da490f689 --- /dev/null +++ b/flake/aspects/editors.nix @@ -0,0 +1,137 @@ +{ den, ... }: +{ + # ── Editors aspect ──────────────────────────────────────────────────────────── + # Home-manager: Neovim, Zed, Emacs, Kakoune. + # Include in a user aspect; enable individual editors via the option flags. + den.aspects.editors = { + homeManager = + { config, lib, pkgs, ... }: + { + options.auscybernix.programs.neovim.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Neovim with custom configuration."; + }; + options.auscybernix.editors.zed.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Zed editor."; + }; + options.auscybernix.editors.emacs.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Emacs editor."; + }; + options.auscybernix.editors.kakoune.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Kakoune editor."; + }; + + config = lib.mkMerge [ + # ── Neovim ────────────────────────────────────────────────────── + (lib.mkIf config.auscybernix.programs.neovim.enable { + age.secrets."wakatime_config" = { + rekeyFile = ../../secrets/wakatime_config.age; + path = "${config.home.homeDirectory}/.wakatime.cfg"; + }; + home.file.".config/nvim".source = + config.lib.file.linkLocalPath ../../.config/nvim; + home.packages = with pkgs; [ + (wrapNeovimUnstable neovim { + wrapRc = false; + vimAlias = true; + withNodeJs = true; + }) + ]; + home.sessionVariables = { + vim = "nvim"; + EDITOR = "nvim"; + editor = "$EDITOR"; + }; + home.file."${config.auscybernix.flakeConfig.flakeFolder}/.config/nvim/lua/treesitter_compiler.lua".text = '' + return "${pkgs.stdenv.cc}/bin/cc" + ''; + }) + + # ── Zed ───────────────────────────────────────────────────────── + (lib.mkIf config.auscybernix.editors.zed.enable { + programs.zed-editor = { + enable = true; + extensions = [ "wakatime" "nix" "toml" "lua" "make" ]; + extraPackages = with pkgs; [ + nodejs yarn rust-analyzer ripgrep nil + ]; + userSettings = { + assistant = { + enabled = true; + version = "2"; + default_open_ai_model = null; + default_model = { + provider = "copilot_chat"; + model = "claude-3-5-sonnet-latest"; + }; + }; + node = { + path = lib.getExe pkgs.nodejs; + npm_path = lib.getExe' pkgs.nodejs "npm"; + }; + hour_format = "hour24"; + auto_update = false; + terminal = { + alternate_scroll = "off"; + blinking = "off"; + copy_on_select = false; + dock = "bottom"; + detect_venv.on = { + directories = [ ".env" "env" ".venv" "venv" ]; + activate_script = "default"; + }; + env.TERM = "alacritty"; + font_family = "FiraCode Nerd Font"; + font_size = null; + line_height = "comfortable"; + option_as_meta = false; + button = false; + shell = "system"; + inlay_hints.enabled = true; + toolbar.title = true; + working_directory = "current_project_directory"; + }; + lsp = { + rust-analyzer.binary.path_lookup = true; + nix.binary.path_lookup = true; + }; + vim_mode = true; + load_direnv = "shell_hook"; + base_keymap = "VSCode"; + show_whitespaces = "all"; + }; + }; + }) + + # ── Emacs ──────────────────────────────────────────────────────── + (lib.mkIf config.auscybernix.editors.emacs.enable { + programs.emacs = { + enable = true; + package = pkgs.emacsNativeComp; + }; + services.emacs.enable = true; + }) + + # ── Kakoune ────────────────────────────────────────────────────── + (lib.mkIf config.auscybernix.editors.kakoune.enable { + programs.kakoune = { + enable = true; + plugins = with pkgs.kakounePlugins; [ + kak-lsp + parinfer-rust + kakoune-extra-filetypes + powerline-kak + ]; + }; + }) + ]; + }; + }; +} diff --git a/flake/aspects/gaming.nix b/flake/aspects/gaming.nix new file mode 100644 index 000000000..413b31ad0 --- /dev/null +++ b/flake/aspects/gaming.nix @@ -0,0 +1,69 @@ +{ den, ... }: +{ + # ── Gaming aspect ───────────────────────────────────────────────────────────── + # NixOS: Steam, gamescope, gamemode, proton. + # Home-manager: Prism Launcher (Minecraft). + # Include in a host aspect (nixos) and/or a user aspect (homeManager). + den.aspects.gaming = { + nixos = + { config, lib, pkgs, ... }: + { + options.auscybernix.nixos.games.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable gaming related programs and settings."; + }; + + config = lib.mkIf config.auscybernix.nixos.games.enable { + programs.gamescope = { + enable = true; + capSysNice = false; + }; + environment.systemPackages = with pkgs; [ + gamescope-wsi + mangohud + ]; + programs.gamemode.enable = true; + programs.steam = { + enable = true; + extraCompatPackages = with pkgs; [ + proton-ge-bin + vkd3d-proton + ]; + package = pkgs.steam.override { + extraPkgs = + pkgs': with pkgs'; [ + libXcursor + libXi + libXinerama + libXScrnSaver + libpng + libpulseaudio + libvorbis + mangohud + stdenv.cc.cc.lib + gamescope + gamemode + gamescope-wsi + libkrb5 + keyutils + ]; + }; + protontricks.enable = true; + gamescopeSession.enable = true; + }; + }; + }; + + homeManager = + { config, lib, pkgs, ... }: + { + options.auscybernix.programs.prismlauncher.enable = + lib.mkEnableOption "Prism Launcher (Minecraft)"; + + config = lib.mkIf config.auscybernix.programs.prismlauncher.enable { + programs.prismlauncher.enable = true; + }; + }; + }; +} diff --git a/flake/aspects/gpg.nix b/flake/aspects/gpg.nix new file mode 100644 index 000000000..38833f1e6 --- /dev/null +++ b/flake/aspects/gpg.nix @@ -0,0 +1,32 @@ +{ den, ... }: +{ + # ── GPG aspect ──────────────────────────────────────────────────────────────── + # Home-manager: GPG extra socket + public key import. + # Include in a user aspect to configure the GPG agent extra socket and import + # the user's public key. + den.aspects.gpg = { + homeManager = + { config, lib, pkgs, ... }: + { + options.services.gpg-agent.socketAddress = lib.mkOption { + type = lib.types.str; + description = "Path to the GPG agent extra socket."; + }; + + config = lib.mkIf config.services.gpg-agent.enableExtraSocket ( + lib.mkMerge [ + { + services.gpg-agent.socketAddress = + if pkgs.stdenv.hostPlatform.isDarwin then + config.launchd.agents.gpg-agent.config.Sockets.std.SockPathName + else + config.systemd.user.gpg-agent.config.sockets.gpg-agent-extra; + programs.gpg.publicKeys = [ + { source = ../../publickey.asc; } + ]; + } + ] + ); + }; + }; +} diff --git a/flake/aspects/keybinds.nix b/flake/aspects/keybinds.nix new file mode 100644 index 000000000..55f05565a --- /dev/null +++ b/flake/aspects/keybinds.nix @@ -0,0 +1,226 @@ +{ den, ... }: +{ + # ── Keybinds aspect ─────────────────────────────────────────────────────────── + # Home-manager: Kanata keyboard remapper (Linux + macOS), Skhd (macOS). + # Darwin system: KMonad (macOS via Karabiner driver), Karabiner-DK service, + # sudoers entries for Kanata. + # Include in a user/host aspect to deploy keyboard remapping tools. + den.aspects.keybinds = { + homeManager = + { config, lib, pkgs, ... }: + let + cfgKanata = config.auscybernix.keybinds.kanata; + cfgSkhd = config.auscybernix.keybinds.skhd; + inherit (pkgs.stdenv.hostPlatform) isDarwin isLinux; + outputFile = pkgs.writeText "kanata-config.kbd" '' + (include ${cfgKanata.config}) + ${lib.concatStringsSep "\n" (map (p: "(include " + p + ")") cfgKanata.extraConfigPaths)} + ''; + defaultTrayConfig = pkgs.writers.writeTOML "kanata-tray-config" + (lib.recursiveUpdate cfgKanata.tray.config { + defaults.kanata_config = "~/.config/kanata/kanata.kbd"; + defaults.autorestart_on_crash = true; + defaults.autorun = true; + }); + in + { + options.auscybernix.keybinds.kanata = with lib.types; { + enable = lib.mkOption { type = bool; default = false; description = "Enable kanata."; }; + extraPackages = lib.mkOption { type = listOf package; default = [ ]; }; + kanataPort = lib.mkOption { type = int; default = 5829; }; + appBundleIds = lib.mkOption { type = listOf str; default = [ ]; }; + package = lib.mkOption { type = package; default = pkgs.kanata-with-cmd; }; + config = lib.mkOption { + type = str; + default = "${pkgs.kanata}/share/kanata/kanata.kbd"; + description = "Path to the base kanata config file."; + }; + extraConfigPaths = lib.mkOption { type = listOf path; default = [ ]; }; + kanataCommand = lib.mkOption { type = listOf str; default = [ "" ]; }; + tray = { + package = lib.mkPackageOption pkgs "kanata-tray" { }; + command = lib.mkOption { type = listOf str; default = [ "" ]; }; + config = lib.mkOption { type = attrs; default = ""; }; + configFile = lib.mkOption { type = path; default = defaultTrayConfig; }; + }; + extraCommandPiping = lib.mkOption { type = nullOr path; default = null; }; + }; + options.auscybernix.keybinds.skhd = { + enable = lib.mkOption { type = lib.types.bool; default = false; }; + binds = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = { }; }; + }; + + config = lib.mkMerge [ + # ── Kanata (shared) ─────────────────────────────────────────────── + (lib.mkIf cfgKanata.enable (lib.mkMerge [ + # Linux + (lib.mkIf isLinux { + systemd.user.services.kanata = { + Unit = { + Description = "Kanata keyboard remapper"; + PartOf = [ config.wayland.systemd.target ]; + After = [ "network.target" "dbus.service" config.wayland.systemd.target ]; + }; + Install.WantedBy = [ config.wayland.systemd.target ]; + Service.ExecStart = + "${cfgKanata.package}/bin/kanata -c '${cfgKanata.config}' -p ${toString cfgKanata.kanataPort}"; + Service.Restart = "no"; + }; + home.packages = [ cfgKanata.package ] ++ cfgKanata.extraPackages; + }) + # macOS + (lib.mkIf isDarwin { + auscybernix.keybinds.kanata.kanataCommand = lib.mkDefault [ + "${cfgKanata.package}/bin/kanata" + "-p" "${toString cfgKanata.kanataPort}" + "-c" "${outputFile}" + ]; + auscybernix.keybinds.kanata.tray.command = lib.mkDefault [ + "${cfgKanata.tray.package}/bin/kanata-tray" + ]; + home.file.".config/kanata/kanata.kbd".source = outputFile; + home.file."Library/Application Support/kanata-tray/kanata-tray.toml".source = + cfgKanata.tray.configFile; + launchd.agents.kanata-vk-agent = { + enable = true; + config = { + Label = "org.nixos.kanata-vk-agent"; + ProgramArguments = + [ "${pkgs.kanata-vk-agent}/bin/kanata-vk-agent" + "-p" "${toString cfgKanata.kanataPort}" + "-b" "${builtins.concatStringsSep "," cfgKanata.appBundleIds}" + ] + ++ (lib.optionals (cfgKanata.extraCommandPiping != null) [ + "-e" (builtins.toString cfgKanata.extraCommandPiping) + ]); + RunAtLoad = true; + KeepAlive = { Crashed = true; SuccessfulExit = false; }; + StandardErrorPath = "/tmp/kanata-vk-agent.err"; + StandardOutPath = "/tmp/kanata-vk-agent.out"; + }; + }; + launchd.agents.kanata_tray = { + enable = true; + config = { + ProgramArguments = [ "/usr/bin/sudo" "-E" ] ++ cfgKanata.tray.command; + StandardErrorPath = "/tmp/kanata_tray.err"; + StandardOutPath = "/tmp/kanata_tray.out"; + RunAtLoad = true; + KeepAlive = true; + EnvironmentVariables = { + KANATA_TRAY_LOG_DIR = "/tmp"; + PATH = "/usr/bin/:/sbin:/bin:/usr/local/bin:" + + lib.makeBinPath ([ cfgKanata.package ] ++ cfgKanata.extraPackages); + }; + }; + }; + launchd.agents.kanata = { + enable = false; + config = { + ProgramArguments = [ "/usr/bin/sudo" "-E" ] ++ cfgKanata.kanataCommand; + StandardErrorPath = "/tmp/kanata_tray.err"; + StandardOutPath = "/tmp/kanata_tray.out"; + RunAtLoad = true; + KeepAlive = true; + EnvironmentVariables = { + PATH = "/usr/bin/:/sbin:/bin:/usr/local/bin:" + + lib.makeBinPath ([ cfgKanata.package ] ++ cfgKanata.extraPackages); + }; + }; + }; + home.packages = [ cfgKanata.package ]; + }) + ])) + + # ── Skhd (macOS only) ───────────────────────────────────────────── + (lib.mkIf cfgSkhd.enable { + services.skhd = { + enable = true; + config = + let + keys = builtins.attrNames cfgSkhd.binds; + rows = map (v: "${v} : ${builtins.getAttr v cfgSkhd.binds}") keys; + in + builtins.concatStringsSep "\n" rows; + }; + home.file."keybinds.json".text = builtins.toJSON cfgSkhd.binds; + }) + ]; + }; + + # ── KMonad + Karabiner-DK (macOS system) ───────────────────────────────── + darwin = + { config, lib, pkgs, ... }: + let + cfgKmonad = config.auscybernix.keybinds.kmonad; + cfgKdk = config.auscybernix.keybinds.karabiner-driver-kit; + in + { + options.auscybernix.keybinds.kmonad = { + enable = lib.mkOption { type = lib.types.bool; default = false; description = "Enable KMonad."; }; + extraPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = [ ]; }; + config = lib.mkOption { + type = lib.types.str; + default = "${pkgs.kmonad}/share/kmonad/kmonad.kbd"; + }; + }; + options.auscybernix.keybinds.karabiner-driver-kit = { + enable = lib.mkOption { type = lib.types.bool; default = false; }; + package = lib.mkOption { type = lib.types.package; default = pkgs.karabiner-dk; }; + }; + + config = lib.mkMerge [ + (lib.mkIf cfgKdk.enable { + services.karabiner-dk = { + enable = true; + package = cfgKdk.package; + }; + }) + + (lib.mkIf cfgKmonad.enable ( + let + defcfg = '' + (defcfg + input (iokit-name) + output (kext) + fallthrough true + allow-cmd true + ) + ''; + kmonadConfigFile = pkgs.writeText "kmonad.kbd" (defcfg + "\n" + cfgKmonad.config); + in + { + environment.systemPackages = with pkgs; [ kmonad ]; + auscybernix.keybinds.karabiner-driver-kit.enable = true; + security.sudo.extraConfig = builtins.readFile ( + pkgs.runCommand "sudoers-kmonad" { } '' + KMONAD_BIN="${pkgs.kmonad}/bin/kmonad" + SHASUM=$(sha256sum "$KMONAD_BIN" | cut -d' ' -f1) + cat <"$out" + ${config.system.primaryUser} ALL=(root) SETENV: NOPASSWD: sha256:$SHASUM $KMONAD_BIN ${kmonadConfigFile} + EOF + '' + ); + launchd.user.agents.kmonad = { + serviceConfig = { + ProgramArguments = [ + "/usr/bin/sudo" "-E" + "${pkgs.kmonad}/bin/kmonad" + "${kmonadConfigFile}" + ]; + Label = "org.nixos.kmonad"; + RunAtLoad = true; + KeepAlive = true; + StandardErrorPath = "/tmp/kmonad.log"; + StandardOutPath = "/tmp/kmonad.log"; + }; + environment.PATH = + "/usr/sbin:/bin:/usr/bin:/sbin:/usr/local/bin:" + + lib.makeBinPath (cfgKmonad.extraPackages ++ [ pkgs.kmonad ]); + }; + } + )) + ]; + }; + }; +} diff --git a/flake/aspects/languages.nix b/flake/aspects/languages.nix new file mode 100644 index 000000000..4b33ca1d3 --- /dev/null +++ b/flake/aspects/languages.nix @@ -0,0 +1,41 @@ +{ den, ... }: +{ + # ── Languages aspect ────────────────────────────────────────────────────────── + # Home-manager: Agda (with standard-library, cubical, agda-categories), + # Idris2 (with LSP and Prettier). + # Include in a user aspect to enable formal-methods / functional language tools. + den.aspects.languages = { + homeManager = + { config, lib, pkgs, ... }: + { + options.auscybernix.languages.agda.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Agda and useful libraries."; + }; + options.auscybernix.languages.idris2.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Idris2 language tools."; + }; + + config = lib.mkMerge [ + (lib.mkIf config.auscybernix.languages.agda.enable { + home.packages = with pkgs; [ + (agda.withPackages (p: with p; [ + standard-library + cubical + agda-categories + ])) + ]; + }) + + (lib.mkIf config.auscybernix.languages.idris2.enable { + home.packages = + (with pkgs.idris2Pkgs; [ lsp Prettier ]) + ++ [ pkgs.idris2 ]; + }) + ]; + }; + }; +} diff --git a/flake/aspects/media.nix b/flake/aspects/media.nix new file mode 100644 index 000000000..aa9fc4b46 --- /dev/null +++ b/flake/aspects/media.nix @@ -0,0 +1,62 @@ +{ den, ... }: +{ + # ── Media aspect ───────────────────────────────────────────────────────────── + # Home-manager: Mopidy music server, Vencord (Discord client mod). + # Include in a user aspect to enable media/communication tools. + den.aspects.media = { + homeManager = + { config, lib, pkgs, ... }: + { + options.auscybernix.services.mopidy.enable = + lib.mkEnableOption "Mopidy music server"; + options.auscybernix.programs.vencord.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Vencord (Discord with plugins and themes)."; + }; + + config = lib.mkMerge [ + # ── Mopidy ─────────────────────────────────────────────────────── + (lib.mkIf config.auscybernix.services.mopidy.enable { + # Mopidy configuration is currently commented out upstream pending + # a secrets-enabled listenbrainz token. The option is declared so + # hosts can set it when the service is ready. + }) + + # ── Vencord ─────────────────────────────────────────────────────── + (lib.mkIf config.auscybernix.programs.vencord.enable { + programs.nixcord = { + enable = true; + vesktop.enable = true; + dorion.enable = true; + quickCss = "some CSS"; + config = { + useQuickCss = true; + frameless = true; + plugins.ignoreActivities = { + enable = true; + ignorePlaying = true; + ignoreWatching = true; + }; + }; + dorion = { + theme = "dark"; + zoom = "1.1"; + blur = "acrylic"; + sysTray = true; + openOnStartup = true; + autoClearCache = true; + disableHardwareAccel = false; + rpcServer = true; + rpcProcessScanner = true; + pushToTalk = true; + pushToTalkKeys = [ "RControl" ]; + desktopNotifications = true; + unreadBadge = true; + }; + }; + }) + ]; + }; + }; +} diff --git a/flake/aspects/shell.nix b/flake/aspects/shell.nix new file mode 100644 index 000000000..a9c0896d8 --- /dev/null +++ b/flake/aspects/shell.nix @@ -0,0 +1,202 @@ +{ den, ... }: +{ + # ── Shell aspect ───────────────────────────────────────────────────────────── + # Fish + Zsh shells, git, direnv, nh, eza, fzf, zoxide, attic, starship, gpg. + # Include in a user aspect to enable the full shell environment. + den.aspects.shell = { + homeManager = + { config, lib, pkgs, ... }: + let + cfgShell = config.auscybernix.shell; + cfgFish = config.auscybernix.shell.fish; + cfgZsh = config.auscybernix.shell.zsh; + in + { + options.auscybernix.shell = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable custom shell configuration."; + }; + fish.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Fish shell configuration."; + }; + zsh.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Zsh shell configuration."; + }; + }; + + config = lib.mkIf cfgShell.enable ( + lib.mkMerge [ + { + age.secrets.attic_token = { + rekeyFile = ../../secrets/attickey.age; + }; + age.templates."attic-config" = { + path = "${config.home.homeDirectory}/.config/attic/config.toml"; + dependencies = { + inherit (config.age.secrets) attic_token; + }; + content = + { pkgs, placeholders, ... }: + '' + default-server = "central" + [servers.central] + endpoint = "https://cache.ivymect.in" + token = "${placeholders.attic_token}" + ''; + }; + home.packages = with pkgs; [ attic-client ]; + services.gpg-agent = { + extraConfig = '' + allow-loopback-pinentry + default-cache-ttl 600 + max-cache-ttl 7200 + ttyname $GPG_TTY + enable-ssh-support + debug-level 2 + ''; + enableScDaemon = true; + }; + home.file.".config/starship.toml".source = ../../.config/starship.toml; + programs.gh = { + enable = true; + settings.git_protocol = "ssh"; + }; + programs.zoxide.enable = true; + programs.fzf.enable = true; + programs.nix-your-shell = { + enable = true; + nix-output-monitor.enable = true; + }; + programs.nh.enable = true; + programs.direnv = { + enable = true; + nix-direnv.enable = true; + }; + programs.home-manager.enable = true; + programs.gpg.enable = true; + programs.git = { + enable = true; + settings.user = { + name = "Ivy Pierlot"; + email = "ivyp@outlook.com.au"; + }; + }; + programs.eza = { + enable = true; + git = true; + icons = "auto"; + }; + } + + # ── Fish shell ───────────────────────────────────────────────── + (lib.mkIf cfgFish.enable { + home.packages = with pkgs; [ nix-output-monitor bat starship ]; + home.sessionVariables.BROWSER = "zen"; + programs.fish = { + enable = true; + shellAliases = { + fzf = "fzf --reverse --height 40%"; + vim = "nvim"; + cat = "bat"; + e = "vim"; + ls = "eza --icons --git"; + ll = "ls -la"; + t = "tmux"; + grep = "grep --color=auto"; + hm = "home-manager "; + }; + interactiveShellInit = + # fish + '' + function bind_bang + switch (commandline -t)[-1] + case "!" + commandline -t -- $history[1] + commandline -f repaint + case "*" + commandline -i ! + end + end + + function bind_dollar + switch (commandline -t)[-1] + case "!" + commandline -f backward-delete-char history-token-search-backward + case "*" + commandline -i '$' + end + end + + function fish_user_key_bindings + bind ! bind_bang + bind '$' bind_dollar + end + set fish_greeting + fetch -s + starship init fish | source + ''; + }; + }) + + # ── Zsh shell ────────────────────────────────────────────────── + (lib.mkIf cfgZsh.enable { + programs.eza.enable = true; + home.packages = with pkgs; [ bat ]; + home.file."Music/Phoebe/lyricslist".source = ../../phoebelyrics/lyricslist; + programs.zsh = { + enable = true; + enableCompletion = true; + syntaxHighlighting.enable = true; + history = { + size = 10000; + path = "${config.xdg.dataHome}/zsh/history"; + }; + sessionVariables = { + MANPATH = "\${MANPATH-$(manpath)}:$NPM_PACKAGES/share/man"; + EDITOR = "nvim"; + editor = "$EDITOR"; + BROWSER = "firefox"; + GTK2_RC_FILES = "$HOME/.gtkrc-2.0"; + _JAVA_AWT_WM_NONREPARENTING = 1; + WLR_NO_HARDWARE_CURSORS = 1; + }; + plugins = builtins.map + (package: { name = package.pname; inherit (package) src; }) + (with pkgs; [ + zsh-autosuggestions + nix-zsh-completions + zsh-completions + zsh-nix-shell + zsh-syntax-highlighting + ]); + shellAliases = { + ghc = "stack exec -- ghc"; + fzf = "fzf --reverse --height 40%"; + vim = "nvim"; + cat = "bat"; + e = "vim"; + ls = "exa --icons --git"; + ll = "ls -la"; + t = "tmux"; + grep = "grep --color=auto"; + windows = "sudo grub-reboot 2 && sudo reboot"; + hm = "home-manager --flake $NIXFLAKE#$FLAKENAME"; + }; + initExtra = '' + export PATH=$PATH:~/.cabal/bin:~/go/bin:~/.emacs.d/bin:~/.local/bin:~/.dotnet/tools:/usr/sbin:/snap/bin:$NPM_PACKAGES/bin:~/.luarocks/bin:/usr/local/go/bin:$DENO_INSTALL/bin:/opt/jdk8u292-b10:$IDRIS_PREFIX/bin + fetch -s + eval "$(starship init zsh)" + ''; + }; + }) + ] + ); + }; + }; +} diff --git a/flake/aspects/ssh.nix b/flake/aspects/ssh.nix new file mode 100644 index 000000000..69547156a --- /dev/null +++ b/flake/aspects/ssh.nix @@ -0,0 +1,63 @@ +{ den, ... }: +{ + # ── SSH aspect ──────────────────────────────────────────────────────────────── + # NixOS: OpenSSH server, pam-rssh, sudo. + # Home-manager: SSH client matchBlocks. + # Include in host aspects (nixos) and user aspects (homeManager). + den.aspects.ssh = { + nixos = + { config, lib, pkgs, ... }: + { + options.auscybernix.ssh.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable OpenSSH server with rssh PAM authentication."; + }; + + config = lib.mkIf config.auscybernix.ssh.enable { + services.openssh = { + enable = true; + settings.StreamLocalBindUnlink = "yes"; + }; + security.sudo.enable = true; + environment.etc = lib.concatMapAttrs + (user: value: { + "authorized_keys/${user}.keys" = { + text = builtins.concatStringsSep "\n" value.openssh.authorizedKeys.keys; + }; + }) + (lib.filterAttrs + (name: user: user.isNormalUser && user.openssh.authorizedKeys != null) + config.users.users); + security.pam.services.sudo.rssh = true; + security.pam.rssh = { + enable = true; + settings.cue = true; + settings.cue_prompt = "please touch"; + }; + }; + }; + + homeManager = + { config, lib, pkgs, ... }: + { + options.auscybernix.programs.ssh.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable SSH client configuration."; + }; + + config = lib.mkIf config.auscybernix.programs.ssh.enable { + programs.ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "faggot.sh" = { hostname = "faggot.sh"; user = "ivy"; forwardAgent = true; }; + "secondpc" = { hostname = "121.200.22.213"; forwardAgent = true; user = "auscyber"; }; + "imflo.pet" = { hostname = "imflo.pet"; forwardAgent = true; user = "ivy"; }; + }; + }; + }; + }; + }; +} diff --git a/flake/aspects/terminal.nix b/flake/aspects/terminal.nix new file mode 100644 index 000000000..3d596a311 --- /dev/null +++ b/flake/aspects/terminal.nix @@ -0,0 +1,49 @@ +{ den, ... }: +{ + # ── Terminal aspect ─────────────────────────────────────────────────────────── + # Home-manager: Ghostty terminal emulator. + # Include in a user aspect to deploy Ghostty with custom theming and shaders. + den.aspects.terminal = { + homeManager = + { config, lib, pkgs, ... }: + { + options.auscybernix.terms.ghostty.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Ghostty terminal emulator."; + }; + + config = lib.mkIf config.auscybernix.terms.ghostty.enable { + stylix.targets.ghostty.enable = false; + programs.ghostty = { + enable = true; + themes.pink_ocean = { + foreground = "d0d0d0"; + cursor-color = "eeeeee"; + selection-background = "005f5f"; + selection-foreground = "eeeeee"; + palette = [ + "0=#080808" "1=#ff5f5f" "2=#87d7af" "3=#d7d787" + "4=#5fafd7" "5=#afafff" "6=#5fd7d7" "7=#dadada" + "8=#8a8a8a" "9=#d75f5f" "10=#afd7af" "11=#d7d7af" + "12=#87afd7" "13=#afafd7" "14=#87d7d7" "14=#dadada" + ]; + background = "202020"; + }; + installBatSyntax = false; + settings = { + shell-integration = "none"; + shell-integration-features = "no-path"; + custom-shader = [ + (builtins.toString ../../modules/home/term/ghostty/cursor_warp.glsl) + ]; + cursor-style = "block"; + theme = "pink_ocean"; + font-size = 15; + font-family = "Hasklug Nerd Font"; + }; + }; + }; + }; + }; +} diff --git a/flake/aspects/vpn.nix b/flake/aspects/vpn.nix new file mode 100644 index 000000000..c3e6d06a7 --- /dev/null +++ b/flake/aspects/vpn.nix @@ -0,0 +1,79 @@ +{ den, ... }: +{ + # ── VPN aspect ──────────────────────────────────────────────────────────────── + # NixOS: WireGuard VPN via wg-quick. + # Include in a host aspect to join the WireGuard mesh. + den.aspects.vpn = { + nixos = + { + config, + lib, + pkgs, + flakeConfig, + systemIdentifier, + ... + }: + let + cfg = config.auscybernix.vpn; + in + { + options.auscybernix.vpn = { + enable = lib.mkEnableOption "WireGuard VPN configuration"; + ipAddress = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = "WireGuard VPN IP address assigned to this host."; + }; + serverpubkey = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "Path to the WireGuard server public key file."; + }; + clientpubkey = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "Path to this host's WireGuard public key file."; + }; + endpoint = lib.mkOption { + type = lib.types.str; + default = "pierlot.com.au:51820"; + description = "WireGuard endpoint (host:port)."; + }; + }; + + config = lib.mkIf cfg.enable { + age.secrets.wireguard_key = { + generator.script = + { pkgs, file, ... }: + '' + priv=$(${pkgs.wireguard-tools}/bin/wg genkey) + ${pkgs.wireguard-tools}/bin/wg pubkey <<< "$priv" > ${ + lib.escapeShellArg (lib.removeSuffix ".age" file + ".pub") + } + echo "$priv" + ''; + }; + auscybernix.vpn.ipAddress = + flakeConfig.flake.auscybernix.vpn.configMap."${systemIdentifier}".ipAddress; + auscybernix.vpn.serverpubkey = + ../../systems/x86_64-linux/secondpc/wg_private_key.pub; + auscybernix.vpn.clientpubkey = + builtins.path { + path = config.age.rekey.generatedSecretsDir + "/wireguard_key.pub"; + }; + networking.wg-quick.interfaces.wg0 = { + address = [ "${cfg.ipAddress}/24" ]; + privateKeyFile = config.age.secrets.wireguard_key.path; + dns = [ "1.1.1.1" "10.100.0.1" ]; + peers = [ + { + publicKey = builtins.readFile cfg.serverpubkey; + allowedIPs = [ "10.100.0.0/24" ]; + endpoint = cfg.endpoint; + persistentKeepalive = 25; + } + ]; + }; + }; + }; + }; +} diff --git a/flake/aspects/wm-darwin.nix b/flake/aspects/wm-darwin.nix new file mode 100644 index 000000000..4f9d0980b --- /dev/null +++ b/flake/aspects/wm-darwin.nix @@ -0,0 +1,317 @@ +{ den, ... }: +{ + # ── macOS Window Manager aspect ─────────────────────────────────────────────── + # Home-manager: Yabai (tiling WM), Rift (tiling WM), Sketchybar (status bar), + # JankyBorders (window borders). + # Darwin: Yabai scripting-addition sudo rule (via darwin-desktop sudoagents). + # Include in a user aspect to enable a macOS tiling desktop environment. + den.aspects."wm-darwin" = { + homeManager = + { config, lib, pkgs, ... }: + let + cfgYabai = config.auscybernix.wms.yabai; + cfgRift = config.auscybernix.wms.rift; + cfgSbar = config.auscybernix.programs.sketchybar; + sources = pkgs.callPackage ../../_sources/generated.nix { }; + in + { + # ── services.yabai option declaration (inline) ──────────────────── + options.services.yabai = with lib.types; { + enable = lib.mkOption { type = bool; default = false; }; + package = lib.mkOption { type = path; default = pkgs.yabai; }; + enableScriptingAddition = lib.mkOption { type = bool; default = false; }; + errorLogFile = lib.mkOption { + type = with lib.types; nullOr (either path str); + defaultText = lib.literalExpression + "\${config.home.homeDirectory}/Library/Logs/yabai/err.log"; + }; + outLogFile = lib.mkOption { + type = with lib.types; nullOr (either path str); + defaultText = lib.literalExpression + "\${config.home.homeDirectory}/Library/Logs/yabai/out.log"; + }; + config = lib.mkOption { type = attrs; default = { }; }; + extraConfig = lib.mkOption { type = lib.types.lines; default = ""; }; + }; + + # ── auscybernix WM options ──────────────────────────────────────── + options.auscybernix.wms.yabai = { + enable = lib.mkEnableOption "yabai window manager"; + scratchpads = lib.mkOption { + description = "Scratchpad windows to configure in yabai."; + type = with lib.types; attrsOf (submodule { + options = { + command = lib.mkOption { type = str; default = ""; }; + detectionRules = lib.mkOption { type = attrsOf str; default = [ ]; }; + rules = lib.mkOption { type = listOf str; default = [ ]; }; + }; + }); + }; + }; + options.auscybernix.wms.rift.enable = + lib.mkEnableOption "Rift window manager"; + options.auscybernix.programs.sketchybar.enable = lib.mkOption { + type = lib.types.bool; + default = false; + }; + + config = lib.mkMerge [ + # ── Yabai ───────────────────────────────────────────────────────── + (lib.mkIf cfgYabai.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.yabai" pkgs lib.platforms.darwin) + ]; + services.jankyborders = { + enable = true; + settings = { + active_color = "0xff${config.stylix.base16Scheme.base03}"; + inactive_color = "0xff${config.stylix.base16Scheme.base0D}"; + style = "round"; + width = 6.0; + }; + }; + auscybernix.keybinds.kanata.extraConfigPaths = [ + (pkgs.writeText "yabai-bindings" '' + toggle_beeper_scratchpad (t! runasuser "yabai -m window --toggle beeper || open -a 'Beeper\ Desktop'") + minimise (t! runasuser "yabai -m window --minimize") + toggle_1password_scratchpad (t! runasuser "yabai -m window --toggle 1password || open -a '1Password'") + toggle_discord_scratchpad (t! runasuser "yabai -m window --toggle discord || open -a Discord") + switch-focus (t! runasuser "yabai -m window --focus next") + reverse-switch-focus (t! runasuser "yabai -m window --focus prev") + kill-focus (t! runasuser "yabai -m window --close") + 1s (t! runasuser "yabai -m space --focus 1") + 2s (t! runasuser "yabai -m space --focus 2") + 3s (t! runasuser "yabai -m space --focus 3") + 4s (t! runasuser "yabai -m space --focus 4") + 5s (t! runasuser "yabai -m space --focus 5") + 6s (t! runasuser "yabai -m space --focus 6") + 7s (t! runasuser "yabai -m space --focus 7") + 8s (t! runasuser "yabai -m space --focus 8") + 9s (t! runasuser "yabai -m space --focus 9") + 10s (t! runasuser "yabai -m space --focus 10") + 1m (t! runasuser "yabai -m window --space 1") + 2m (t! runasuser "yabai -m window --space 2") + 3m (t! runasuser "yabai -m window --space 3") + 4m (t! runasuser "yabai -m window --space 4") + 5m (t! runasuser "yabai -m window --space 5") + 6m (t! runasuser "yabai -m window --space 6") + 7m (t! runasuser "yabai -m window --space 7") + 8m (t! runasuser "yabai -m window --space 8") + 9m (t! runasuser "yabai -m window --space 9") + 10m (t! runasuser "yabai -m window --space 10") + dm (t! runasuser "yabai -m window --display recent") + '') + ]; + services.yabai = { + enable = true; + enableScriptingAddition = true; + config = { + focus_follows_mouse = "off"; + mouse_follows_focus = "off"; + window_placement = "second_child"; + window_opacity = "off"; + external_bar = "main:40:0"; + layout = "bsp"; + top_padding = 10; + bottom_padding = 6; + left_padding = 10; + right_padding = 10; + window_gap = 10; + }; + extraConfig = + (lib.concatMapAttrsStringSep "\n" + (name: sp: + let + rules = lib.concatStringsSep " " sp.rules; + value = "${ + lib.concatMapAttrsStringSep " " (k: v: "${k}=\"${v}\"") sp.detectionRules + } manage=off sticky=on scratchpad=${name} ${rules}"; + in + '' + # Scratchpad: ${name} + yabai -m rule --add ${value} + yabai -m rule --apply ${value} + '') + cfgYabai.scratchpads) + + '' + yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa" + sudo yabai --load-sa + yabai -m rule --add app="^System Preferences$" manage=off + yabai -m signal --add app='^Ghostty$' event=window_created action='yabai -m space --layout bsp' + yabai -m signal --add app='^Ghostty$' event=window_destroyed action='yabai -m space --layout bsp' + ''; + errorLogFile = lib.mkOptionDefault + "${config.home.homeDirectory}/Library/Logs/yabai/yabai.err.log"; + outLogFile = lib.mkOptionDefault + "${config.home.homeDirectory}/Library/Logs/yabai/yabai.out.log"; + }; + home.packages = [ config.services.yabai.package ]; + launchd.agents.yabai = { + enable = true; + config = { + ProcessType = "Interactive"; + ProgramArguments = + [ "${config.services.yabai.package}/bin/yabai" ] + ++ lib.optionals + (config.services.yabai.config != { } || config.services.yabai.extraConfig != "") + [ + "-c" + ( + let + toYabaiConfig = opts: + lib.concatStringsSep "\n" + (lib.mapAttrsToList (p: v: "yabai -m config ${p} ${toString v}") opts); + configFile = + pkgs.writeScript "yabairc" + ((if config.services.yabai.config != { } then + "${toYabaiConfig config.services.yabai.config}" + else "") + + lib.optionalString (config.services.yabai.extraConfig != "") + ("\n" + config.services.yabai.extraConfig + "\n")); + in + "${configFile}" + ) + ]; + EnvironmentVariables.PATH = + "${config.services.yabai.package}/bin:/usr/bin:/bin:/usr/sbin:/sbin"; + KeepAlive = true; + RunAtLoad = true; + StandardErrorPath = config.services.yabai.errorLogFile; + StandardOutPath = config.services.yabai.outLogFile; + }; + }; + auscybernix.wms.yabai.scratchpads = { + "1password" = { detectionRules = { app = "^1Password$"; }; rules = [ "grid=11:11:1:1:9:9" ]; }; + "discord" = { detectionRules = { app = "^Discord$"; "title!" = "^Discord Updater$"; }; rules = [ "grid=11:11:1:1:9:9" ]; }; + "beeper" = { detectionRules = { app = "^Beeper$"; "title!" = "^Beeper Updater$"; }; rules = [ "grid=11:11:1:1:9:9" ]; }; + }; + }) + + # ── Rift ────────────────────────────────────────────────────────── + (lib.mkIf cfgRift.enable { + imports = [ ../../modules/home/wms/rift/internal ]; + services.jankyborders = { + enable = true; + settings = { + active_color = "0xff${config.stylix.base16Scheme.base03}"; + inactive_color = "0xff${config.stylix.base16Scheme.base0D}"; + style = "round"; + width = 6.0; + }; + }; + auscybernix.keybinds.kanata.extraConfigPaths = [ + (pkgs.writeText "rift-keybinds" + # commonlisp + '' + (defalias + enable_spaces (t! runasuser "rift-cli execute window toggle-space-activated ") + toggle_discord_scratchpad (t! runasuser "rift-cli execute window toggle-scratchpad --name discord || open -a Discord") + toggle_beeper_scratchpad (t! runasuser " rift-cli execute window toggle-scratchpad --name beeper || open -a 'Beeper\ Desktop'") + minimise (t! runasuser "yabai -m window --minimize") + toggle_1password_scratchpad (t! runasuser "rift-cli execute window toggle-scratchpad --name 1password || open -a '1Password'") + switch-focus (t! runasuser "yabai -m window --focus next") + reverse-switch-focus (t! runasuser "yabai -m window --focus prev") + kill-focus (t! runasuser "rift-cli query windows | jq '.[] | select(.is_focused) | .window_server_id' | xargs -I{} rift-cli execute window close --window-id {}") + 1s (t! runasuser "rift-cli execute workspace switch 0") + 2s (t! runasuser "rift-cli execute workspace switch 1") + 3s (t! runasuser "rift-cli execute workspace switch 2") + 4s (t! runasuser "rift-cli execute workspace switch 3") + 5s (t! runasuser "rift-cli execute workspace switch 4") + 6s (t! runasuser "rift-cli execute workspace switch 5") + 7s (t! runasuser "rift-cli execute workspace switch 6") + 8s (t! runasuser "rift-cli execute workspace switch 7") + 9s (t! runasuser "rift-cli execute workspace switch 8") + 10s (t! runasuser "rift-cli execute workspace switch 10") + 1m (t! runasuser "rift-cli execute workspace move-window 0") + 2m (t! runasuser "rift-cli execute workspace move-window 1") + 3m (t! runasuser "rift-cli execute workspace move-window 2") + 4m (t! runasuser "rift-cli execute workspace move-window 3") + 5m (t! runasuser "rift-cli execute workspace move-window 4") + 6m (t! runasuser "rift-cli execute workspace move-window 5") + 7m (t! runasuser "rift-cli execute workspace move-window 6") + 8m (t! runasuser "rift-cli execute workspace move-window 7") + 9m (t! runasuser "rift-cli execute workspace move-window 8") + 10m (t! runasuser "rift-cli execute workspace move-window 10") + shiftUp (t! runasuser "rift-cli execute display move-window --direction up") + shiftDown (t! runasuser "rift-cli execute display move-window --direction down") + shiftLeft (t! runasuser "rift-cli execute display move-window --direction left") + shiftRight (t! runasuser "rift-cli execute display move-window --direction right") + focusUp (t! runasuser "rift-cli execute display focus --direction up") + focusDown (t! runasuser "rift-cli execute display focus --direction down") + focusLeft (t! runasuser "rift-cli execute display focus --direction left") + focusRight (t! runasuser "rift-cli execute display focus --direction right")) + '') + ]; + services.rift = { + enable = true; + package = pkgs.rift; + extraPackages = with pkgs; [ rift sketchybar ]; + settings = { + settings = { + run_on_start = [ + "rift-cli subscribe cli --event workspace_changed --command /bin/sh --args -c --args 'sketchybar --trigger rift_workspace_changed FOCUSED_WORKSPACE=\\\"$RIFT_WORKSPACE_NAME\\\"'" + "rift-cli subscribe cli --event windows_changed --command /bin/sh --args -c --args 'sketchybar --trigger rift_windows_changed RIFT_WORKSPACE_NAME=\\\"$RIFT_WORKSPACE_NAME\\\" RIFT_WINDOW_COUNT=\\\"$RIFT_WINDOW_COUNT\\\"'" + "rift-cli subscribe cli --event window_title_changed --command /bin/sh --args -c --args 'sketchybar --trigger rift_windows_title'" + ]; + default_disable = false; + layout.gaps.outer = { top = 15; left = 10; right = 10; bottom = 5; }; + layout.mode = "bsp"; + focus_follows_mouse = false; + mouse_follows_focus = false; + gestures = { enabled = true; fingers = 3; }; + }; + virtual_workspaces = { + enabled = true; + default_workspace_count = 5; + workspace_names = [ "Main" "Dev" "Chat" "Media" "Misc" ]; + app_rules = [ + { app_id = "com.hnc.Discord"; scratchpad = "discord"; } + { app_id = "com.automattic.beeper.desktop"; scratchpad = "beeper"; } + { app_id = "com.agilebits.onepassword7"; scratchpad = "1password"; } + ]; + }; + keys."Alt + Z" = "toggle_space_activated"; + }; + }; + }) + + # ── Sketchybar ──────────────────────────────────────────────────── + (lib.mkIf cfgSbar.enable { + home.packages = with pkgs; [ yq jq ]; + home.file."${config.auscybernix.flakeConfig.flakeFolder}/.config/sketchybar/colors.sh" = { + text = + let colors = config.stylix.base16Scheme; in + '' + #!/bin/bash + # generated by stylix — do not edit manually + export COLOR_BACKGROUND='${colors.base00}' + export COLOR_BLACK='${colors.base01}' + export COLOR_SELECTION='${colors.base02}' + export COLOR_COMMENT='${colors.base03}' + export COLOR_DARKGRAY='${colors.base04}' + export COLOR_FOREGROUND='${colors.base05}' + export COLOR_BRIGHTWHITE='${colors.base06}' + export COLOR_WHITE='${colors.base07}' + export COLOR_RED='${colors.base08}' + export COLOR_ORANGE='${colors.base09}' + export COLOR_YELLOW='${colors.base0A}' + export COLOR_GREEN='${colors.base0B}' + export COLOR_CYAN='${colors.base0C}' + export COLOR_BLUE='${colors.base0D}' + export COLOR_MAGENTA='${colors.base0E}' + export COLOR_BROWN='${colors.base0F}' + ''; + }; + home.file.".config/sketchybar".source = + config.lib.file.linkLocalPath ../../.config/sketchybar; + home.file.".config/icon_map.sh".source = sources.icon_map.src; + programs.sketchybar = { + service.enable = true; + enable = true; + extraPackages = with pkgs; [ jq yq yabai nowplaying-cli rift ]; + }; + }) + ]; + }; + }; +} diff --git a/flake/aspects/wm-linux.nix b/flake/aspects/wm-linux.nix new file mode 100644 index 000000000..001090924 --- /dev/null +++ b/flake/aspects/wm-linux.nix @@ -0,0 +1,169 @@ +{ den, ... }: +{ + # ── Linux Window Manager aspect ─────────────────────────────────────────────── + # Home-manager: Hyprland (Wayland), Niri (Wayland), Picom (X11 compositor). + # Include in a user aspect to configure Linux desktop window management. + den.aspects."wm-linux" = { + homeManager = + { config, lib, pkgs, inputs, ... }: + let + cfgHypr = config.auscybernix.wms.hyprland; + cfgNiri = config.auscybernix.wms.niri; + cfgPicom = config.auscybernix.programs.picom; + in + { + options.auscybernix.wms.hyprland = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Hyprland Wayland compositor."; + }; + scratchpads = lib.mkOption { + default = { }; + type = lib.types.attrsOf (lib.types.submodule { + options = { + command = lib.mkOption { type = lib.types.str; default = ""; }; + windowClass = lib.mkOption { type = lib.types.str; default = ""; }; + extraRules = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; }; + }; + }); + }; + }; + options.auscybernix.wms.niri.enable = + lib.mkEnableOption "Niri Wayland compositor"; + options.auscybernix.programs.picom = lib.mkOption { + type = lib.types.attrsOf lib.types.any; + default = { }; + description = "Picom compositor configuration options."; + }; + + config = lib.mkMerge [ + # ── Hyprland ───────────────────────────────────────────────────── + (lib.mkIf cfgHypr.enable { + home.packages = with pkgs; [ hyprpolkitagent ]; + programs.wofi.enable = true; + wayland.windowManager.hyprland = { + package = null; + portalPackage = null; + enable = true; + xwayland.enable = true; + plugins = with pkgs.hyprlandPlugins; [ hyprbars ]; + extraConfig = '' + monitor = , highres, auto, 1.5 + + xwayland { + force_zero_scaling = true + } + + env = GDK_SCALE,2 + env = XCURSOR_SIZE,32 + decoration { + rounding = 10 + rounding_power = 2 + active_opacity = 1.0 + inactive_opacity = 1.0 + shadow { + enabled = true + range = 4 + render_power = 3 + color = rgba(1a1a1aee) + } + blur { + enabled = true + size = 3 + passes = 1 + vibrancy = 0.1696 + } + } + general { + gaps_in = 5 + gaps_out = 20 + border_size = 2 + resize_on_border = false + allow_tearing = false + layout = dwindle + } + ''; + settings = + lib.foldAttrs (item: acc: if builtins.isList item then acc ++ item else item) [ ] + [ + (lib.foldAttrs (item: acc: acc ++ item) [ ] ( + lib.attrsets.mapAttrsToList (name: sc: { + windowrule = [ + "workspace special:${name}, class:${sc.windowClass}" + "float, class:${sc.windowClass}" + ] ++ builtins.map (rule: "${rule}, class:${sc.windowClass}") sc.extraRules; + exec-once = [ ("[workspace special:${name}]" + sc.command) ]; + }) cfgHypr.scratchpads + )) + { + "$mod" = "SUPER"; + env = [ + "LIBVA_DRIVER_NAME,nvidia" + "__GLX_VENDOR_LIBRARY_NAME,nvidia" + "NVD_BACKEND,direct" + "ELECTRON_OZONE_PLATFORM_HINT,auto" + ]; + exec-once = [ + "systemctl --user stop graphical-session.target && systemctl --user start hyprland-session.target" + "1password" + "systemctl --user start hyprpolkitagent" + ]; + } + ]; + }; + programs.hyprpanel = { + enable = true; + systemd.enable = true; + settings = { + bar.launcher.autoDetectIcon = true; + bar.workspaces.show_icons = true; + menus.clock = { + time = { military = true; hideSeconds = true; }; + weather.unit = "metric"; + }; + menus.dashboard.directories.enabled = false; + menus.dashboard.stats.enable_gpu = true; + theme.bar.transparent = true; + theme.font = { name = "CaskaydiaCove NF"; size = "16px"; }; + }; + }; + }) + + # ── Niri ────────────────────────────────────────────────────────── + (lib.mkIf cfgNiri.enable { + programs.niri = { + enable = true; + settings = { }; + }; + }) + + # ── Picom ───────────────────────────────────────────────────────── + (lib.mkIf cfgPicom.enable { + services.picom = { + enable = true; + experimentalBackends = true; + fade = false; + shadow = false; + shadowOffsets = [ (-30) (-30) ]; + shadowOpacity = "0.25"; + shadowExclude = [ "name = 'xmonad'" ]; + blur = true; + blurExclude = [ "class_g = 'slop'" ]; + vSync = true; + refreshRate = 60; + extraOptions = '' + corner-radius = 5.0; + rounded-corners-exclude = [ + "class_g = 'Polybar'", + "class_g = 'Minecraft* 1.16.4'", + "class_g = 'xmobar'" + ] + round-borders = 1; + ''; + }; + }) + ]; + }; + }; +} From 3d03f0fcbeedb3181316f5d4e8db14f49284abd2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 02:06:53 +0000 Subject: [PATCH 5/5] Complete darwin aspects and add angle-bracket feature includes for user aspects Agent-Logs-Url: https://github.com/auscyber/dotfiles/sessions/709f081d-5005-44f3-849a-5407ca86c79d Co-authored-by: auscyber <12080502+auscyber@users.noreply.github.com> --- flake/aspects/auscyber.nix | 20 +++++++++++++++++++- flake/aspects/defaults.nix | 11 +++++++++-- flake/aspects/ivypierlot.nix | 19 ++++++++++++++++++- flake/aspects/macmini.nix | 9 +++++++-- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/flake/aspects/auscyber.nix b/flake/aspects/auscyber.nix index 48c3ce804..ed3e0f546 100644 --- a/flake/aspects/auscyber.nix +++ b/flake/aspects/auscyber.nix @@ -1,4 +1,8 @@ -{ ... }: +{ den, ... }: +let + # Enable syntax for den aspect references in this file. + __findFile = den.lib.__findFile; +in { den.aspects.auscyber = { # Base home-manager configuration shared across all hosts where auscyber @@ -11,6 +15,20 @@ username = "auscyber"; homeDirectory = "/home/auscyber"; }; + programs.home-manager.enable = true; }; + + # Feature aspects included for all auscyber homes (Linux hosts). + includes = [ + + + + + + + + + + ]; }; } diff --git a/flake/aspects/defaults.nix b/flake/aspects/defaults.nix index e243ecc24..f8b578eb2 100644 --- a/flake/aspects/defaults.nix +++ b/flake/aspects/defaults.nix @@ -1,12 +1,19 @@ { config, inputs, - # Enable syntax for den battery references. - __findFile ? __findFile, den, ... }: +let + # Enable syntax for den battery references in this file. + # This must be defined before the angle-bracket expressions below. + __findFile = den.lib.__findFile; +in { + # Propagate den's bracket resolver to all flake-parts modules so that any + # module accepting `__findFile` as an argument automatically gets den's + # resolver rather than the NIX_PATH fall-back. + _module.args.__findFile = den.lib.__findFile; # ── NixOS defaults ────────────────────────────────────────────────────────── den.default.nixos = { imports = [ diff --git a/flake/aspects/ivypierlot.nix b/flake/aspects/ivypierlot.nix index be023f3bc..f46591dc4 100644 --- a/flake/aspects/ivypierlot.nix +++ b/flake/aspects/ivypierlot.nix @@ -1,4 +1,8 @@ -{ ... }: +{ den, ... }: +let + # Enable syntax for den aspect references in this file. + __findFile = den.lib.__findFile; +in { den.aspects.ivypierlot = { # Base home-manager configuration shared across all hosts where ivypierlot @@ -11,6 +15,19 @@ username = "ivypierlot"; homeDirectory = "/Users/ivypierlot"; }; + programs.home-manager.enable = true; }; + + # Feature aspects included for all ivypierlot homes (Darwin hosts). + includes = [ + + + + + + + + + ]; }; } diff --git a/flake/aspects/macmini.nix b/flake/aspects/macmini.nix index 8d282e138..7edd697ef 100644 --- a/flake/aspects/macmini.nix +++ b/flake/aspects/macmini.nix @@ -4,7 +4,12 @@ darwin = { ... }: { imports = [ ../../systems/aarch64-darwin/macmini ]; }; - # No dedicated home configuration for macmini; ivypierlot's base - # homeManager aspect applies via den.aspects.ivypierlot.homeManager. + + # ivypierlot on macmini: the shared feature aspects arrive via + # den.aspects.ivypierlot.includes; only macmini-specific home-manager + # additions are placed here. + provides.ivypierlot = { ... }: { + homeManager = { ... }: { }; + }; }; }