Compare commits
75 Commits
boxy-app-l
...
25.11
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ae4d84ca2 | |||
| 7c877fde84 | |||
| d53286e04c | |||
| 445b0cd558 | |||
| 6d9686f14b | |||
| 4164832eea | |||
| ade60ba5ec | |||
| 48fb7cdada | |||
| 2d8cfe75a0 | |||
| 385fd798de | |||
| fe6558e0c1 | |||
| b9c48f9dd1 | |||
| 34351403d1 | |||
| 12820ce9ff | |||
| 0f5eb2e572 | |||
| f356c91fdb | |||
| 6b42612135 | |||
| 50a8c44d10 | |||
| 7011fb27a5 | |||
| 1ff8b81f44 | |||
| 55f13dfb08 | |||
| 63bf19b85f | |||
| 1f9e9138ab | |||
| e218822566 | |||
| e88f3580e9 | |||
| 5451e75480 | |||
| fc9474a7c9 | |||
| 20daebbd61 | |||
| 3be23304c4 | |||
| 9059a739a0 | |||
| 977125645b | |||
| a9772259f0 | |||
| 4f6d65316a | |||
| 0b8e3bf527 | |||
| d3c906134b | |||
| 30b616dd93 | |||
| c9252c42c2 | |||
| fa7cb55c78 | |||
| 2283b0a6df | |||
| 4ea9437bb0 | |||
| d0760a22bd | |||
| f67a12c29a | |||
| fc8a43504d | |||
| 4a73b3a5ae | |||
| be68202523 | |||
| 608fed35ab | |||
| c2e2dd8675 | |||
| 5750f737f1 | |||
| c27518e0dc | |||
| 7f318edc4d | |||
| f995240153 | |||
| d62bae0ddb | |||
| 79ae42f41d | |||
| 0c15aad5c0 | |||
| d87793d39b | |||
| fad6e61aac | |||
| 1bc65ceb51 | |||
| bda76c6abc | |||
| c42e09e972 | |||
| 4d986c0b48 | |||
| 4e3fdd78d2 | |||
| d3703fc5a9 | |||
| 35c2ebb592 | |||
| 569ac528a5 | |||
| 6cc8fa4f5d | |||
| 67a82f14fd | |||
| 4b68e3f051 | |||
| 81a3657759 | |||
| 32e1b81034 | |||
| 6f00c72540 | |||
| d26007aa61 | |||
| 1caa8bba3e | |||
| d3cb09040a | |||
| 4bfacffa17 | |||
| a6961f05ca |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
result
|
result
|
||||||
|
thoughts
|
||||||
|
|||||||
163
flake.lock
generated
163
flake.lock
generated
@@ -3,11 +3,11 @@
|
|||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1747046372,
|
"lastModified": 1761588595,
|
||||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
"narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1752428473,
|
"lastModified": 1761423376,
|
||||||
"narHash": "sha256-IsE7fdAYbRlZuc0H5FtPfhhuHvlxnDGoAxdlnjpVNCU=",
|
"narHash": "sha256-pMy3cnUFfue4vz/y0jx71BfcPGxZf+hk/DtnzWvfU0c=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "1fad66b55144ab6beaecd900172a21ac3c34dc52",
|
"rev": "a1f695665771841a988afc965526cbf99160cd77",
|
||||||
"revCount": 10,
|
"revCount": 11,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.johnogle.info/johno/google-cookie-retrieval.git"
|
"url": "https://git.johnogle.info/johno/google-cookie-retrieval.git"
|
||||||
},
|
},
|
||||||
@@ -43,19 +43,62 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759172751,
|
"lastModified": 1764866045,
|
||||||
"narHash": "sha256-E8W8sRXfrvkFW26GuuiWq6QfReU7m5+cngwHuRo/3jc=",
|
"narHash": "sha256-0GsEtXV9OquDQ1VclQfP16cU5VZh7NEVIOjSH4UaJuM=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "12fa8548feefa9a10266ba65152fd1a787cdde8f",
|
"rev": "f63d0fe9d81d36e5fc95497217a72e02b8b7bcab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
|
"ref": "release-25.11",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"home-manager-unstable": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764872372,
|
||||||
|
"narHash": "sha256-uZuXRz9CzeCHsRbc2MQvKomwoX6GcFC5BUMEk3ouSFU=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "05a56dbf24f195c62286e3273a2671d3b4904b00",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jovian": {
|
||||||
|
"inputs": {
|
||||||
|
"nix-github-actions": "nix-github-actions",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764746434,
|
||||||
|
"narHash": "sha256-6ymFuw+Z1C90ezf8H0BP3c2JFZhJYwMq31px2StwWHU=",
|
||||||
|
"owner": "Jovian-Experiments",
|
||||||
|
"repo": "Jovian-NixOS",
|
||||||
|
"rev": "b4c0b604148adacf119b89824ed26df8926ce42c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Jovian-Experiments",
|
||||||
|
"repo": "Jovian-NixOS",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nix-darwin": {
|
"nix-darwin": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -63,30 +106,53 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758805352,
|
"lastModified": 1764161084,
|
||||||
"narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=",
|
"narHash": "sha256-HN84sByg9FhJnojkGGDSrcjcbeioFWoNXfuyYfJ1kBE=",
|
||||||
"owner": "nix-darwin",
|
"owner": "nix-darwin",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"rev": "c48e963a5558eb1c3827d59d21c5193622a1477c",
|
"rev": "e95de00a471d07435e0527ff4db092c84998698e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-darwin",
|
"owner": "nix-darwin",
|
||||||
|
"ref": "nix-darwin-25.11",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-github-actions": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"jovian",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1729697500,
|
||||||
|
"narHash": "sha256-VFTWrbzDlZyFHHb1AlKRiD/qqCJIripXKiCSFS8fAOY=",
|
||||||
|
"owner": "zhaofengli",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"rev": "e418aeb728b6aa5ca8c5c71974e7159c2df1d8cf",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "zhaofengli",
|
||||||
|
"ref": "matrix-name",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixos-wsl": {
|
"nixos-wsl": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758785683,
|
"lastModified": 1764730608,
|
||||||
"narHash": "sha256-mRn51IeEBXeNh5a6xNLylk4PKBX0s/QQxgkEbYoPq/w=",
|
"narHash": "sha256-FxKIa3OCSRVC23qrk7VT68vExUcmSruJ8OobVlSWOxc=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NixOS-WSL",
|
"repo": "NixOS-WSL",
|
||||||
"rev": "1bfb978f2f6261b6086e04af17f9418e1fe36d70",
|
"rev": "10124c58674360765adcb38c9a8b081fb72904e4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -98,11 +164,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758277210,
|
"lastModified": 1764517877,
|
||||||
"narHash": "sha256-iCGWf/LTy+aY0zFu8q12lK8KuZp7yvdhStehhyX1v8w=",
|
"narHash": "sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "8eaee110344796db060382e15d3af0a9fc396e0e",
|
"rev": "2d293cbfa5a793b4c50d17c05ef9e385b90edf6c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -112,13 +178,13 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759036355,
|
"lastModified": 1764667669,
|
||||||
"narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
|
"narHash": "sha256-7WUCZfmqLAssbDqwg9cUDAXrSoXN79eEEq17qhTNM/Y=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
|
"rev": "418468ac9527e799809c900eda37cbff999199b6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -128,6 +194,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764677808,
|
||||||
|
"narHash": "sha256-H3lC7knbXOBrHI9hITQ7modLuX20mYJVhZORL5ioms0=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1aab89277eb2d87823d5b69bae631a2496cff57a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-25.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"plasma-manager": {
|
"plasma-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"home-manager": [
|
"home-manager": [
|
||||||
@@ -138,11 +220,34 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759157415,
|
"lastModified": 1763909441,
|
||||||
"narHash": "sha256-Fg8cOnVoIe0uQ38UpR6XZzRCwDsjjozVwfevW9yCLI0=",
|
"narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "plasma-manager",
|
"repo": "plasma-manager",
|
||||||
"rev": "df5b3e6da631f732c26c6044c7cccb8706b4f479",
|
"rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "plasma-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plasma-manager-unstable": {
|
||||||
|
"inputs": {
|
||||||
|
"home-manager": [
|
||||||
|
"home-manager-unstable"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1763909441,
|
||||||
|
"narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "plasma-manager",
|
||||||
|
"rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -155,10 +260,14 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"google-cookie-retrieval": "google-cookie-retrieval",
|
"google-cookie-retrieval": "google-cookie-retrieval",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
|
"home-manager-unstable": "home-manager-unstable",
|
||||||
|
"jovian": "jovian",
|
||||||
"nix-darwin": "nix-darwin",
|
"nix-darwin": "nix-darwin",
|
||||||
"nixos-wsl": "nixos-wsl",
|
"nixos-wsl": "nixos-wsl",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"plasma-manager": "plasma-manager"
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
|
"plasma-manager": "plasma-manager",
|
||||||
|
"plasma-manager-unstable": "plasma-manager-unstable"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
98
flake.nix
98
flake.nix
@@ -2,41 +2,97 @@
|
|||||||
description = "A very basic flake";
|
description = "A very basic flake";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
|
||||||
|
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
|
nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
|
||||||
|
|
||||||
nix-darwin = {
|
nix-darwin = {
|
||||||
url = "github:nix-darwin/nix-darwin";
|
url = "github:nix-darwin/nix-darwin/nix-darwin-25.11";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager = {
|
home-manager = {
|
||||||
url = "github:nix-community/home-manager";
|
url = "github:nix-community/home-manager/release-25.11";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home-manager-unstable = {
|
||||||
|
url = "github:nix-community/home-manager/master";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
plasma-manager = {
|
plasma-manager = {
|
||||||
url = "github:nix-community/plasma-manager";
|
url = "github:nix-community/plasma-manager";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
inputs.home-manager.follows = "home-manager";
|
inputs.home-manager.follows = "home-manager";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
plasma-manager-unstable = {
|
||||||
|
url = "github:nix-community/plasma-manager";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
inputs.home-manager.follows = "home-manager-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
google-cookie-retrieval = {
|
google-cookie-retrieval = {
|
||||||
url = "git+https://git.johnogle.info/johno/google-cookie-retrieval.git";
|
url = "git+https://git.johnogle.info/johno/google-cookie-retrieval.git";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jovian = {
|
||||||
|
url = "github:Jovian-Experiments/Jovian-NixOS";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, nixos-wsl, ... } @ inputs: let
|
outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let
|
||||||
nixosModules = [
|
nixosModules = [
|
||||||
./roles
|
./roles
|
||||||
] ++ [
|
] ++ [
|
||||||
inputs.home-manager.nixosModules.home-manager
|
inputs.home-manager.nixosModules.home-manager
|
||||||
{
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
unstable = import nixpkgs-unstable {
|
||||||
|
system = prev.system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
custom = prev.callPackage ./packages {};
|
||||||
|
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||||
|
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
|
||||||
|
})
|
||||||
|
];
|
||||||
home-manager.useGlobalPkgs = true;
|
home-manager.useGlobalPkgs = true;
|
||||||
home-manager.useUserPackages = true;
|
home-manager.useUserPackages = true;
|
||||||
home-manager.sharedModules = [
|
home-manager.sharedModules = [
|
||||||
inputs.plasma-manager.homeManagerModules.plasma-manager
|
inputs.plasma-manager.homeModules.plasma-manager
|
||||||
|
];
|
||||||
|
home-manager.extraSpecialArgs = {
|
||||||
|
globalInputs = inputs;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
# Modules for unstable-based systems (like nix-deck)
|
||||||
|
nixosModulesUnstable = [
|
||||||
|
./roles
|
||||||
|
] ++ [
|
||||||
|
inputs.home-manager-unstable.nixosModules.home-manager
|
||||||
|
inputs.jovian.nixosModules.jovian
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
unstable = import nixpkgs-unstable {
|
||||||
|
system = prev.system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
custom = prev.callPackage ./packages {};
|
||||||
|
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||||
|
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
home-manager.useGlobalPkgs = true;
|
||||||
|
home-manager.useUserPackages = true;
|
||||||
|
home-manager.sharedModules = [
|
||||||
|
inputs.plasma-manager-unstable.homeModules.plasma-manager
|
||||||
];
|
];
|
||||||
home-manager.extraSpecialArgs = {
|
home-manager.extraSpecialArgs = {
|
||||||
globalInputs = inputs;
|
globalInputs = inputs;
|
||||||
@@ -48,6 +104,24 @@
|
|||||||
] ++ [
|
] ++ [
|
||||||
inputs.home-manager.darwinModules.home-manager
|
inputs.home-manager.darwinModules.home-manager
|
||||||
{
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
unstable = import nixpkgs-unstable {
|
||||||
|
system = prev.system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
overlays = [
|
||||||
|
# Override claude-code in unstable to use our custom GCS-based build
|
||||||
|
# (needed for corporate networks that block npm registry)
|
||||||
|
(ufinal: uprev: {
|
||||||
|
claude-code = prev.custom.claude-code or (prev.callPackage ./packages {}).claude-code;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
custom = prev.callPackage ./packages {};
|
||||||
|
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||||
|
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
|
||||||
|
})
|
||||||
|
];
|
||||||
home-manager.useGlobalPkgs = true;
|
home-manager.useGlobalPkgs = true;
|
||||||
home-manager.useUserPackages = true;
|
home-manager.useUserPackages = true;
|
||||||
home-manager.extraSpecialArgs = {
|
home-manager.extraSpecialArgs = {
|
||||||
@@ -65,7 +139,7 @@
|
|||||||
home-manager.users.johno = {
|
home-manager.users.johno = {
|
||||||
imports = [ ./home/home-laptop-compact.nix ];
|
imports = [ ./home/home-laptop-compact.nix ];
|
||||||
# Machine-specific overrides
|
# Machine-specific overrides
|
||||||
home.i3_sway.extraSwayConfig = {
|
home.roles.i3_sway.extraSwayConfig = {
|
||||||
output.eDP-1.scale = "1.75";
|
output.eDP-1.scale = "1.75";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -123,6 +197,18 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Steam Deck configuration (using unstable for better Jovian compatibility)
|
||||||
|
nixosConfigurations.nix-deck = nixpkgs-unstable.lib.nixosSystem rec {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
modules = nixosModulesUnstable ++ [
|
||||||
|
./machines/nix-deck/configuration.nix
|
||||||
|
{
|
||||||
|
home-manager.users.johno = import ./home/home-desktop.nix;
|
||||||
|
home-manager.extraSpecialArgs = { inherit system; };
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
# Darwin/macOS configurations
|
# Darwin/macOS configurations
|
||||||
darwinConfigurations."blkfv4yf49kt7" = inputs.nix-darwin.lib.darwinSystem rec {
|
darwinConfigurations."blkfv4yf49kt7" = inputs.nix-darwin.lib.darwinSystem rec {
|
||||||
system = "aarch64-darwin";
|
system = "aarch64-darwin";
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
customPkgs = pkgs.callPackage ../packages {};
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
# Provide arguments to role modules
|
|
||||||
_module.args = { inherit customPkgs; };
|
|
||||||
# Home Manager configuration for Darwin work laptop
|
# Home Manager configuration for Darwin work laptop
|
||||||
# Corporate-friendly setup with essential development tools
|
# Corporate-friendly setup with essential development tools
|
||||||
|
|
||||||
@@ -13,28 +8,86 @@ in
|
|||||||
home.homeDirectory = lib.mkForce "/Users/johno";
|
home.homeDirectory = lib.mkForce "/Users/johno";
|
||||||
home.stateVersion = "24.05";
|
home.stateVersion = "24.05";
|
||||||
|
|
||||||
|
# System packages
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
google-cloud-sdk
|
||||||
|
];
|
||||||
|
|
||||||
|
# Note: ghostty installed via Homebrew (managed outside of nix)
|
||||||
|
|
||||||
# Override Darwin-incompatible settings from base role
|
# Override Darwin-incompatible settings from base role
|
||||||
programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac;
|
programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac;
|
||||||
|
|
||||||
programs.bash.initExtra = ''
|
# Disable Home Manager from managing shell RC files
|
||||||
export NODE_EXTRA_CA_CERTS=/opt/homebrew/etc/ca-certificates/cert.pem
|
# topsoil/compost will manage these files instead
|
||||||
export COREPACK_NPM_REGISTRY=https://global.block-artifacts.com/artifactory/api/npm/square-npm/
|
programs.bash.enable = lib.mkForce false;
|
||||||
export COREPACK_INTEGRITY_KEYS=0
|
programs.zsh.enable = lib.mkForce false;
|
||||||
|
|
||||||
export NVM_DIR="$HOME/.nvm"
|
# Create a local nix integration file that topsoil-managed configs can source
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
|
home.file.".nix-integration.sh" = {
|
||||||
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
|
text = ''
|
||||||
'';
|
# Source Home Manager session variables (nix paths, environment, etc.)
|
||||||
|
if [ -e /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh ]; then
|
||||||
|
. /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh
|
||||||
|
fi
|
||||||
|
|
||||||
programs.zsh.enable = true;
|
# Setup bash completions from nix profiles
|
||||||
programs.zsh.initContent = ''
|
if [[ ! -v BASH_COMPLETION_VERSINFO ]] && [ -n "$NIX_PROFILES" ]; then
|
||||||
export NODE_EXTRA_CA_CERTS=/opt/homebrew/etc/ca-certificates/cert.pem
|
for profile in $NIX_PROFILES; do
|
||||||
export COREPACK_NPM_REGISTRY=https://global.block-artifacts.com/artifactory/api/npm/square-npm/
|
if [ -f "$profile/etc/profile.d/bash_completion.sh" ]; then
|
||||||
export COREPACK_INTEGRITY_KEYS=0
|
. "$profile/etc/profile.d/bash_completion.sh"
|
||||||
export NVM_DIR="$HOME/.nvm"
|
break
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
|
fi
|
||||||
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" # This loads nvm bash_completion
|
done
|
||||||
'';
|
fi
|
||||||
|
|
||||||
|
# command-not-found handler
|
||||||
|
command_not_found_handle() {
|
||||||
|
local p=/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite
|
||||||
|
if [ -n "$NIX_PROFILES" ]; then
|
||||||
|
for profile in $NIX_PROFILES; do
|
||||||
|
if [ -x "$profile/bin/command-not-found" ] && [ -f "$p" ]; then
|
||||||
|
"$profile/bin/command-not-found" "$@"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo "$1: command not found" >&2
|
||||||
|
return 127
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
home.file.".nix-integration.zsh" = {
|
||||||
|
text = ''
|
||||||
|
# Source Home Manager session variables (nix paths, environment, etc.)
|
||||||
|
if [ -e /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh ]; then
|
||||||
|
. /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup zsh completions from nix profiles
|
||||||
|
typeset -U path cdpath fpath manpath
|
||||||
|
for profile in ''${(z)NIX_PROFILES}; do
|
||||||
|
fpath+=($profile/share/zsh/site-functions $profile/share/zsh/$ZSH_VERSION/functions $profile/share/zsh/vendor-completions)
|
||||||
|
done
|
||||||
|
autoload -U compinit && compinit
|
||||||
|
|
||||||
|
# command-not-found handler
|
||||||
|
command_not_found_handler() {
|
||||||
|
local p=/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite
|
||||||
|
if [ -n "$NIX_PROFILES" ]; then
|
||||||
|
for profile in ''${(z)NIX_PROFILES}; do
|
||||||
|
if [ -x "$profile/bin/command-not-found" ] && [ -f "$p" ]; then
|
||||||
|
"$profile/bin/command-not-found" "$@"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo "$1: command not found" >&2
|
||||||
|
return 127
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
# Keep SSH and Git disabled to avoid conflicts with work environment
|
# Keep SSH and Git disabled to avoid conflicts with work environment
|
||||||
programs.ssh.enable = lib.mkForce false;
|
programs.ssh.enable = lib.mkForce false;
|
||||||
@@ -45,12 +98,26 @@ in
|
|||||||
|
|
||||||
home.roles = {
|
home.roles = {
|
||||||
base.enable = true;
|
base.enable = true;
|
||||||
|
development = {
|
||||||
|
enable = true;
|
||||||
|
allowArbitraryClaudeCodeModelSelection = true;
|
||||||
|
};
|
||||||
|
tmux.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
aerospace = {
|
||||||
|
enable = true;
|
||||||
|
leader = "cmd";
|
||||||
|
ctrlShortcuts.enable = true;
|
||||||
|
sketchybar.enable = true;
|
||||||
|
# Optional: Add per-machine userSettings overrides
|
||||||
|
# userSettings = {
|
||||||
|
# mode.main.binding."${leader}-custom" = "custom-command";
|
||||||
|
# };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-darwin
|
||||||
./modules/kubectl
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
{ pkgs, globalInputs, system, ... }:
|
{ pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
customPkgs = pkgs.callPackage ../packages {};
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
# Provide arguments to role modules
|
|
||||||
_module.args = { inherit customPkgs; };
|
|
||||||
# Home Manager configuration for full desktop experience
|
# Home Manager configuration for full desktop experience
|
||||||
home.username = "johno";
|
home.username = "johno";
|
||||||
home.homeDirectory = "/home/johno";
|
home.homeDirectory = "/home/johno";
|
||||||
@@ -21,6 +16,11 @@ in
|
|||||||
communication.enable = true;
|
communication.enable = true;
|
||||||
sync.enable = true;
|
sync.enable = true;
|
||||||
kdeconnect.enable = true;
|
kdeconnect.enable = true;
|
||||||
|
kubectl.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
targets.genericLinux.enable = true;
|
targets.genericLinux.enable = true;
|
||||||
@@ -29,10 +29,6 @@ in
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
customPkgs = pkgs.callPackage ../packages {};
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
# Provide arguments to role modules
|
|
||||||
_module.args = { inherit customPkgs; };
|
|
||||||
# Home Manager configuration for compact laptop setups
|
# Home Manager configuration for compact laptop setups
|
||||||
# Optimized for space-constrained environments
|
# Optimized for space-constrained environments
|
||||||
|
|
||||||
@@ -22,7 +17,19 @@ in
|
|||||||
kdeconnect.enable = true;
|
kdeconnect.enable = true;
|
||||||
media.enable = true;
|
media.enable = true;
|
||||||
sync.enable = true;
|
sync.enable = true;
|
||||||
# office.enable = false; # Excluded for storage constraints
|
kubectl.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
|
|
||||||
|
# Launcher wrappers for excluded/optional packages
|
||||||
|
launchers = {
|
||||||
|
enable = true;
|
||||||
|
packages = [
|
||||||
|
"libreoffice"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
targets.genericLinux.enable = true;
|
targets.genericLinux.enable = true;
|
||||||
@@ -31,11 +38,6 @@ in
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
{ pkgs, globalInputs, system, ... }:
|
{ pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
customPkgs = pkgs.callPackage ../packages {};
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
# Provide arguments to role modules
|
|
||||||
_module.args = { inherit customPkgs; };
|
|
||||||
# Home Manager configuration for live USB environments
|
# Home Manager configuration for live USB environments
|
||||||
# Minimal setup without persistent services
|
# Minimal setup without persistent services
|
||||||
|
|
||||||
@@ -17,8 +12,12 @@ in
|
|||||||
home.roles = {
|
home.roles = {
|
||||||
base.enable = true;
|
base.enable = true;
|
||||||
desktop.enable = true;
|
desktop.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
# development.enable = false; # Not needed for live USB
|
# development.enable = false; # Not needed for live USB
|
||||||
# communication.enable = false; # Not needed for live USB
|
# communication.enable = false; # Not needed for live USB
|
||||||
# office.enable = false; # Not needed for live USB
|
# office.enable = false; # Not needed for live USB
|
||||||
# media.enable = false; # Not needed for live USB
|
# media.enable = false; # Not needed for live USB
|
||||||
# sync.enable = false; # No persistent sync on live USB
|
# sync.enable = false; # No persistent sync on live USB
|
||||||
@@ -31,11 +30,7 @@ in
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# Live USB specific overrides can go here if needed
|
# Live USB specific overrides can go here if needed
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
{ pkgs, globalInputs, system, ... }:
|
{ pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
customPkgs = pkgs.callPackage ../packages {};
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
# Provide arguments to role modules
|
|
||||||
_module.args = { inherit customPkgs; };
|
|
||||||
# Home Manager configuration for media center setups
|
# Home Manager configuration for media center setups
|
||||||
# Optimized for living room media consumption and gaming
|
# Optimized for living room media consumption and gaming
|
||||||
|
|
||||||
@@ -21,6 +16,10 @@ in
|
|||||||
communication.enable = true;
|
communication.enable = true;
|
||||||
kdeconnect.enable = true;
|
kdeconnect.enable = true;
|
||||||
development.enable = true;
|
development.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
# office.enable = false; # Not needed for media center
|
# office.enable = false; # Not needed for media center
|
||||||
# sync.enable = false; # Shared machine, no personal file sync
|
# sync.enable = false; # Shared machine, no personal file sync
|
||||||
};
|
};
|
||||||
@@ -31,11 +30,7 @@ in
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# Media center specific overrides can go here if needed
|
# Media center specific overrides can go here if needed
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.home.i3_sway;
|
|
||||||
i3_cfg = config.xsession.windowManager.i3.config;
|
|
||||||
|
|
||||||
shared_config = recursiveUpdate rec {
|
|
||||||
modifier = "Mod4";
|
|
||||||
terminal = "kitty";
|
|
||||||
defaultWorkspace = "workspace number 1";
|
|
||||||
|
|
||||||
keybindings = {
|
|
||||||
"${shared_config.modifier}+Return" = "exec ${terminal}";
|
|
||||||
"${shared_config.modifier}+Shift+q" = "kill";
|
|
||||||
"${shared_config.modifier}+d" = "exec ${i3_cfg.menu}";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+h" = "focus left";
|
|
||||||
"${shared_config.modifier}+j" = "focus down";
|
|
||||||
"${shared_config.modifier}+k" = "focus up";
|
|
||||||
"${shared_config.modifier}+l" = "focus right";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+h" = "move left";
|
|
||||||
"${shared_config.modifier}+Shift+j" = "move down";
|
|
||||||
"${shared_config.modifier}+Shift+k" = "move up";
|
|
||||||
"${shared_config.modifier}+Shift+l" = "move right";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Left" = "focus left";
|
|
||||||
"${shared_config.modifier}+Down" = "focus down";
|
|
||||||
"${shared_config.modifier}+Up" = "focus up";
|
|
||||||
"${shared_config.modifier}+Right" = "focus right";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+Left" = "move left";
|
|
||||||
"${shared_config.modifier}+Shift+Down" = "move down";
|
|
||||||
"${shared_config.modifier}+Shift+Up" = "move up";
|
|
||||||
"${shared_config.modifier}+Shift+Right" = "move right";
|
|
||||||
|
|
||||||
#"${shared_config.modifier}+h" = "split h";
|
|
||||||
"${shared_config.modifier}+v" = "split v";
|
|
||||||
"${shared_config.modifier}+f" = "fullscreen toggle";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+s" = "layout stacking";
|
|
||||||
"${shared_config.modifier}+w" = "layout tabbed";
|
|
||||||
"${shared_config.modifier}+e" = "layout toggle split";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+space" = "floating toggle";
|
|
||||||
"${shared_config.modifier}+space" = "focus mode_toggle";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+a" = "focus parent";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+minus" = "move scratchpad";
|
|
||||||
"${shared_config.modifier}+minus" = "scratchpad show";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+1" = "workspace number 1";
|
|
||||||
"${shared_config.modifier}+2" = "workspace number 2";
|
|
||||||
"${shared_config.modifier}+3" = "workspace number 3";
|
|
||||||
"${shared_config.modifier}+4" = "workspace number 4";
|
|
||||||
"${shared_config.modifier}+5" = "workspace number 5";
|
|
||||||
"${shared_config.modifier}+6" = "workspace number 6";
|
|
||||||
"${shared_config.modifier}+7" = "workspace number 7";
|
|
||||||
"${shared_config.modifier}+8" = "workspace number 8";
|
|
||||||
"${shared_config.modifier}+9" = "workspace number 9";
|
|
||||||
"${shared_config.modifier}+0" = "workspace number 10";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+1" =
|
|
||||||
"move container to workspace number 1";
|
|
||||||
"${shared_config.modifier}+Shift+2" =
|
|
||||||
"move container to workspace number 2";
|
|
||||||
"${shared_config.modifier}+Shift+3" =
|
|
||||||
"move container to workspace number 3";
|
|
||||||
"${shared_config.modifier}+Shift+4" =
|
|
||||||
"move container to workspace number 4";
|
|
||||||
"${shared_config.modifier}+Shift+5" =
|
|
||||||
"move container to workspace number 5";
|
|
||||||
"${shared_config.modifier}+Shift+6" =
|
|
||||||
"move container to workspace number 6";
|
|
||||||
"${shared_config.modifier}+Shift+7" =
|
|
||||||
"move container to workspace number 7";
|
|
||||||
"${shared_config.modifier}+Shift+8" =
|
|
||||||
"move container to workspace number 8";
|
|
||||||
"${shared_config.modifier}+Shift+9" =
|
|
||||||
"move container to workspace number 9";
|
|
||||||
"${shared_config.modifier}+Shift+0" =
|
|
||||||
"move container to workspace number 10";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+c" = "reload";
|
|
||||||
"${shared_config.modifier}+Shift+r" = "restart";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+r" = "mode resize";
|
|
||||||
|
|
||||||
"XF86MonBrightnessUp" = "exec brightnessctl s +5%";
|
|
||||||
"XF86MonBrightnessDown" = "exec brightnessctl s 5%-";
|
|
||||||
};
|
|
||||||
} cfg.extraSharedConfig;
|
|
||||||
in {
|
|
||||||
options.home.i3_sway = {
|
|
||||||
extraSharedConfig = mkOption {
|
|
||||||
default = {};
|
|
||||||
};
|
|
||||||
extraI3Config = mkOption {
|
|
||||||
default = {};
|
|
||||||
};
|
|
||||||
extraSwayConfig = mkOption {
|
|
||||||
default = {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
xsession.windowManager.i3 = let
|
|
||||||
base_i3_config = recursiveUpdate shared_config {
|
|
||||||
keybindings = {
|
|
||||||
"${shared_config.modifier}+Shift+e" =
|
|
||||||
"exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
enable = true;
|
|
||||||
config = recursiveUpdate base_i3_config cfg.extraI3Config;
|
|
||||||
};
|
|
||||||
|
|
||||||
wayland.windowManager.sway = let
|
|
||||||
base_sway_config = recursiveUpdate shared_config {
|
|
||||||
keybindings = {
|
|
||||||
"${shared_config.modifier}+Shift+e" =
|
|
||||||
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";
|
|
||||||
};
|
|
||||||
input = {
|
|
||||||
"type:keyboard" = {
|
|
||||||
xkb_options = "caps:escape";
|
|
||||||
};
|
|
||||||
"type:touchpad" = {
|
|
||||||
tap = "enabled";
|
|
||||||
tap_button_map = "lrm";
|
|
||||||
drag = "enabled";
|
|
||||||
natural_scroll = "disabled";
|
|
||||||
dwt = "enabled";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
enable = true;
|
|
||||||
config = recursiveUpdate base_sway_config cfg.extraSwayConfig;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
|
|
||||||
# The current KDE config can be output with the command:
|
|
||||||
# nix run github:nix-community/plasma-manager
|
|
||||||
#
|
|
||||||
# Plasma-manager options documentation
|
|
||||||
# https://nix-community.github.io/plasma-manager/options.xhtml
|
|
||||||
#
|
|
||||||
# TODO: (ambitious) Add Kmail support to plasma-manager
|
|
||||||
{
|
|
||||||
programs.plasma = {
|
|
||||||
enable = true;
|
|
||||||
overrideConfig = true;
|
|
||||||
|
|
||||||
hotkeys.commands."launch-konsole" = {
|
|
||||||
name = "Launch Konsole";
|
|
||||||
key = "Meta+Return";
|
|
||||||
command = "konsole";
|
|
||||||
};
|
|
||||||
|
|
||||||
shortcuts = {
|
|
||||||
kmix = {
|
|
||||||
"decrease_microphone_volume" = "Microphone Volume Down";
|
|
||||||
"decrease_volume" = "Volume Down";
|
|
||||||
"decrease_volume_small" = "Shift+Volume Down";
|
|
||||||
"increase_microphone_volume" = "Microphone Volume Up";
|
|
||||||
"increase_volume" = "Volume Up";
|
|
||||||
"increase_volume_small" = "Shift+Volume Up";
|
|
||||||
"mic_mute" = ["Microphone Mute" "Meta+Volume Mute,Microphone Mute" "Meta+Volume Mute,Mute Microphone"];
|
|
||||||
"mute" = "Volume Mute";
|
|
||||||
};
|
|
||||||
|
|
||||||
mediacontrol = {
|
|
||||||
"mediavolumedown" = "none,,Media volume down";
|
|
||||||
"mediavolumeup" = "none,,Media volume up";
|
|
||||||
"nextmedia" = "Media Next";
|
|
||||||
"pausemedia" = "Media Pause";
|
|
||||||
"playmedia" = "none,,Play media playback";
|
|
||||||
"playpausemedia" = "Media Play";
|
|
||||||
"previousmedia" = "Media Previous";
|
|
||||||
"stopmedia" = "Media Stop";
|
|
||||||
};
|
|
||||||
|
|
||||||
ksmserver = {
|
|
||||||
"Lock Session" = ["Meta+Ctrl+Q" "Screensaver" "Screensaver,Lock Session"];
|
|
||||||
};
|
|
||||||
|
|
||||||
kwin = {
|
|
||||||
"Window Close" = "Meta+Shift+Q";
|
|
||||||
"Kill Window" = "Meta+Ctrl+Esc";
|
|
||||||
"Window Operations Menu" = "Alt+F3";
|
|
||||||
"Window Resize" = "Meta+R,,Resize Window";
|
|
||||||
|
|
||||||
"Overview" = "Meta+Ctrl+W";
|
|
||||||
"Grid View" = "Meta+G";
|
|
||||||
"Edit Tiles" = "Meta+T";
|
|
||||||
|
|
||||||
"Activate Window Demanding Attention" = "Meta+Ctrl+A";
|
|
||||||
|
|
||||||
"Show Desktop" = "Meta+Ctrl+D";
|
|
||||||
|
|
||||||
"Walk Through Windows" = "Alt+Tab";
|
|
||||||
"Walk Through Windows (Reverse)" = "Alt+Shift+Tab";
|
|
||||||
"Walk Through Windows of Current Application" = "Alt+`";
|
|
||||||
"Walk Through Windows of Current Application (Reverse)" = "Alt+~";
|
|
||||||
|
|
||||||
"Window Quick Tile Bottom" = "Meta+Down";
|
|
||||||
"Window Quick Tile Left" = "Meta+Left";
|
|
||||||
"Window Quick Tile Right" = "Meta+Right";
|
|
||||||
"Window Quick Tile Top" = "Meta+Up";
|
|
||||||
|
|
||||||
"Switch to Desktop 1" = "Meta+1";
|
|
||||||
"Switch to Desktop 2" = "Meta+2";
|
|
||||||
"Switch to Desktop 3" = "Meta+3";
|
|
||||||
"Switch to Desktop 4" = "Meta+4";
|
|
||||||
"Switch to Desktop 5" = "Meta+5";
|
|
||||||
"Switch to Desktop 6" = "Meta+6";
|
|
||||||
"Switch to Desktop 7" = "Meta+7";
|
|
||||||
"Switch to Desktop 8" = "Meta+8";
|
|
||||||
"Switch to Desktop 9" = "Meta+9";
|
|
||||||
"Switch to Desktop 10" = "Meta+0";
|
|
||||||
|
|
||||||
"Window to Desktop 1" = "Meta+!"; # Meta+Shift+1
|
|
||||||
"Window to Desktop 2" = "Meta+@"; # Meta+Shift+2
|
|
||||||
"Window to Desktop 3" = "Meta+#"; # Meta+Shift+3
|
|
||||||
"Window to Desktop 4" = "Meta+$"; # Meta+Shift+4
|
|
||||||
"Window to Desktop 5" = "Meta+%"; # Meta+Shift+5
|
|
||||||
"Window to Desktop 6" = "Meta+^"; # Meta+Shift+6
|
|
||||||
"Window to Desktop 7" = "Meta+&"; # Meta+Shift+7
|
|
||||||
"Window to Desktop 8" = "Meta+*"; # Meta+Shift+8
|
|
||||||
"Window to Desktop 9" = "Meta+("; # Meta+Shift+9
|
|
||||||
"Window to Desktop 10" = "Meta+)"; # Meta+Shift+0
|
|
||||||
|
|
||||||
"view_actual_size" = "Meta+Ctrl+=";
|
|
||||||
"view_zoom_in" = ["Meta++" "Meta+=,Meta++" "Meta+=,Zoom In"];
|
|
||||||
"view_zoom_out" = "Meta+-";
|
|
||||||
};
|
|
||||||
"org_kde_powerdevil"."Decrease Keyboard Brightness" = "Keyboard Brightness Down";
|
|
||||||
"org_kde_powerdevil"."Decrease Screen Brightness" = "Monitor Brightness Down";
|
|
||||||
"org_kde_powerdevil"."Decrease Screen Brightness Small" = "Shift+Monitor Brightness Down";
|
|
||||||
"org_kde_powerdevil"."Hibernate" = "Hibernate";
|
|
||||||
"org_kde_powerdevil"."Increase Keyboard Brightness" = "Keyboard Brightness Up";
|
|
||||||
"org_kde_powerdevil"."Increase Screen Brightness" = "Monitor Brightness Up";
|
|
||||||
"org_kde_powerdevil"."Increase Screen Brightness Small" = "Shift+Monitor Brightness Up";
|
|
||||||
"org_kde_powerdevil"."PowerDown" = "Power Down";
|
|
||||||
"org_kde_powerdevil"."PowerOff" = "Power Off";
|
|
||||||
"org_kde_powerdevil"."Sleep" = "Sleep";
|
|
||||||
"org_kde_powerdevil"."Toggle Keyboard Backlight" = "Keyboard Light On/Off";
|
|
||||||
"org_kde_powerdevil"."Turn Off Screen" = [ ];
|
|
||||||
"org_kde_powerdevil"."powerProfile" = ["Battery" "Meta+B,Battery" "Meta+B,Switch Power Profile"];
|
|
||||||
|
|
||||||
plasmashell = {
|
|
||||||
"activate application launcher" = ["Meta" "Alt+F1,Meta" "Alt+F1,Activate Application Launcher"];
|
|
||||||
"activate task manager entry 1" = "none,,";
|
|
||||||
"activate task manager entry 2" = "none,,";
|
|
||||||
"activate task manager entry 3" = "none,,";
|
|
||||||
"activate task manager entry 4" = "none,,";
|
|
||||||
"activate task manager entry 5" = "none,,";
|
|
||||||
"activate task manager entry 6" = "none,,";
|
|
||||||
"activate task manager entry 7" = "none,,";
|
|
||||||
"activate task manager entry 8" = "none,,";
|
|
||||||
"activate task manager entry 9" = "none,,";
|
|
||||||
"activate task manager entry 10" = "none,,";
|
|
||||||
"show activity switcher" = "none,,";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
configFile = {
|
|
||||||
kwinrc.Desktops.Number = {
|
|
||||||
value = 10;
|
|
||||||
immutable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Enable KWin tiling features
|
|
||||||
kwinrc.Tiling = {
|
|
||||||
# Enable tiling functionality
|
|
||||||
"padding" = 4;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Enable krohnkite plugin automatically
|
|
||||||
kwinrc.Plugins = {
|
|
||||||
krohnkiteEnabled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
kwinrc.Effect-overview = {
|
|
||||||
# Configure overview effect for better tiling workflow
|
|
||||||
BorderActivate = 9; # Top-left corner activation
|
|
||||||
};
|
|
||||||
|
|
||||||
kcminputrc.Libinput = {
|
|
||||||
AccelerationProfile = "adaptive";
|
|
||||||
PointerAcceleration = 0.5;
|
|
||||||
};
|
|
||||||
|
|
||||||
kcminputrc.Mouse = {
|
|
||||||
X11LibInputXAccelProfileFlat = false;
|
|
||||||
XLbInptAccelProfileFlat = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
kdeglobals.KDE.LookAndFeelPackage = "org.kde.breezedark.desktop";
|
|
||||||
|
|
||||||
# Focus follows mouse configuration
|
|
||||||
kwinrc.Windows = {
|
|
||||||
FocusPolicy = "FocusFollowsMouse";
|
|
||||||
AutoRaise = true; # Set to true if you want windows to auto-raise on focus
|
|
||||||
AutoRaiseInterval = 750; # Delay in ms before auto-raise (if enabled)
|
|
||||||
DelayFocusInterval = 0; # Delay in ms before focus follows mouse
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
tokyo-night = pkgs.tmuxPlugins.mkTmuxPlugin {
|
|
||||||
pluginName = "tokyo-night";
|
|
||||||
rtpFilePath = "tokyo-night.tmux";
|
|
||||||
version = "1.6.1";
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "janoamaral";
|
|
||||||
repo = "tokyo-night-tmux";
|
|
||||||
rev = "d610ced20d5f602a7995854931440e4a1e0ab780";
|
|
||||||
sha256 = "sha256-17vEgkL7C51p/l5gpT9dkOy0bY9n8l0/LV51mR1k+V8=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
programs.tmux.enable = true;
|
|
||||||
programs.tmux.terminal = "tmux-direct";
|
|
||||||
programs.tmux.keyMode = "vi";
|
|
||||||
programs.tmux.escapeTime = 0;
|
|
||||||
programs.tmux.mouse = true;
|
|
||||||
programs.tmux.newSession = true;
|
|
||||||
programs.tmux.historyLimit = 50000;
|
|
||||||
programs.tmux.clock24 = true;
|
|
||||||
programs.tmux.baseIndex = 1;
|
|
||||||
programs.tmux.prefix = "M-\\\\";
|
|
||||||
|
|
||||||
programs.tmux.plugins = with pkgs; [
|
|
||||||
tmuxPlugins.cpu
|
|
||||||
tmuxPlugins.battery
|
|
||||||
tmuxPlugins.better-mouse-mode
|
|
||||||
tmuxPlugins.net-speed
|
|
||||||
tmuxPlugins.online-status
|
|
||||||
tmuxPlugins.pain-control
|
|
||||||
tmuxPlugins.tilish
|
|
||||||
tmuxPlugins.yank
|
|
||||||
|
|
||||||
{
|
|
||||||
plugin = tmuxPlugins.resurrect;
|
|
||||||
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
plugin = tmuxPlugins.continuum;
|
|
||||||
extraConfig = ''
|
|
||||||
set -g @continuum-restore 'on'
|
|
||||||
set -g @continuum-save-interval '15' # minutes
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
|
||||||
tokyo-night
|
|
||||||
];
|
|
||||||
}
|
|
||||||
716
home/roles/aerospace/default.nix
Normal file
716
home/roles/aerospace/default.nix
Normal file
@@ -0,0 +1,716 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.aerospace;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.aerospace = {
|
||||||
|
enable = mkEnableOption "AeroSpace tiling window manager for macOS";
|
||||||
|
|
||||||
|
leader = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "cmd";
|
||||||
|
description = "Leader key for aerospace shortcuts (e.g., 'cmd', 'ctrl', 'alt')";
|
||||||
|
example = "ctrl";
|
||||||
|
};
|
||||||
|
|
||||||
|
launchd.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable launchd agent for auto-starting aerospace";
|
||||||
|
};
|
||||||
|
|
||||||
|
userSettings = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Additional aerospace configuration settings to merge with defaults.
|
||||||
|
Use this to override or extend the default configuration on a per-machine basis.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
mode.main.binding."''${leader}-custom" = "custom-command";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
autoraise = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable autoraise (auto-focus window on hover)";
|
||||||
|
};
|
||||||
|
|
||||||
|
pollMillis = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 50;
|
||||||
|
description = "Polling interval in milliseconds";
|
||||||
|
};
|
||||||
|
|
||||||
|
delay = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 2;
|
||||||
|
description = "Delay before raising window";
|
||||||
|
};
|
||||||
|
|
||||||
|
focusDelay = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 2;
|
||||||
|
description = "Delay before focusing window";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
enableSpansDisplays = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Configure macOS Spaces to span displays (required for aerospace multi-monitor support).
|
||||||
|
Sets com.apple.spaces.spans-displays to true.
|
||||||
|
|
||||||
|
NOTE: This was previously set at the system level in modules/aerospace.nix,
|
||||||
|
but has been moved to home-manager for better modularity.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ctrlShortcuts = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Remap common macOS Cmd shortcuts to Ctrl equivalents for all operations.
|
||||||
|
This makes macOS behave more like Linux.
|
||||||
|
|
||||||
|
Shortcuts remapped globally:
|
||||||
|
- Ctrl+N: New Window
|
||||||
|
- Ctrl+T: New Tab
|
||||||
|
- Ctrl+W: Close Tab
|
||||||
|
- Ctrl+S: Save / Save As
|
||||||
|
- Ctrl+O: Open
|
||||||
|
- Ctrl+F: Find
|
||||||
|
- Ctrl+H: Find and Replace
|
||||||
|
- Ctrl+P: Print
|
||||||
|
- Ctrl+C/V/X: Copy/Paste/Cut
|
||||||
|
- Ctrl+Z: Undo
|
||||||
|
|
||||||
|
NOTE: Terminal emulators like Ghostty require per-app overrides (configured separately)
|
||||||
|
to preserve Ctrl+C as SIGINT instead of Copy.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sketchybar = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to enable SketchyBar status bar";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# Only apply on Darwin systems
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = pkgs.stdenv.isDarwin;
|
||||||
|
message = "Aerospace role is only supported on macOS (Darwin) systems";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Configure macOS preferences via targets.darwin.defaults
|
||||||
|
targets.darwin.defaults = mkMerge [
|
||||||
|
# Spaces span displays (required for multi-monitor aerospace)
|
||||||
|
(mkIf cfg.enableSpansDisplays {
|
||||||
|
"com.apple.spaces" = {
|
||||||
|
spans-displays = true;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ctrl shortcuts to make macOS behave more like Linux
|
||||||
|
(mkIf cfg.ctrlShortcuts.enable {
|
||||||
|
NSGlobalDomain.NSUserKeyEquivalents = {
|
||||||
|
# Window/Tab operations
|
||||||
|
"New Window" = "^n";
|
||||||
|
"New Tab" = "^t";
|
||||||
|
"Close Tab" = "^w";
|
||||||
|
# File operations
|
||||||
|
"Save" = "^s";
|
||||||
|
"Save As…" = "^$s"; # Ctrl+Shift+S
|
||||||
|
"Open" = "^o";
|
||||||
|
"Open…" = "^o";
|
||||||
|
# Find operations
|
||||||
|
"Find" = "^f";
|
||||||
|
"Find…" = "^f";
|
||||||
|
"Find and Replace" = "^h";
|
||||||
|
"Find and Replace…" = "^h";
|
||||||
|
# Print
|
||||||
|
"Print" = "^p";
|
||||||
|
"Print…" = "^p";
|
||||||
|
# Clipboard operations
|
||||||
|
"Copy" = "^c";
|
||||||
|
"Paste" = "^v";
|
||||||
|
"Cut" = "^x";
|
||||||
|
# Undo/Redo
|
||||||
|
"Undo" = "^z";
|
||||||
|
"Redo" = "^$z"; # Ctrl+Shift+Z
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ghostty-specific overrides to preserve terminal behavior
|
||||||
|
# Remap clipboard operations back to Cmd (macOS default) so Ctrl+C remains SIGINT
|
||||||
|
(mkIf cfg.ctrlShortcuts.enable {
|
||||||
|
"com.mitchellh.ghostty".NSUserKeyEquivalents = {
|
||||||
|
# Remap back to Cmd for clipboard operations
|
||||||
|
"Copy" = "@c"; # Cmd+C
|
||||||
|
"Paste" = "@v"; # Cmd+V
|
||||||
|
"Cut" = "@x"; # Cmd+X
|
||||||
|
"Undo" = "@z"; # Cmd+Z
|
||||||
|
"Redo" = "@$z"; # Cmd+Shift+Z
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Install aerospace package and optional tools if enabled
|
||||||
|
home.packages = [ pkgs.aerospace ]
|
||||||
|
++ optionals cfg.autoraise.enable [ pkgs.autoraise ]
|
||||||
|
++ optionals cfg.sketchybar.enable [ pkgs.sketchybar pkgs.sketchybar-app-font ];
|
||||||
|
|
||||||
|
# Enable and configure aerospace
|
||||||
|
programs.aerospace.enable = true;
|
||||||
|
programs.aerospace.launchd.enable = cfg.launchd.enable;
|
||||||
|
programs.aerospace.userSettings = mkMerge [
|
||||||
|
# Default configuration with leader key substitution
|
||||||
|
{
|
||||||
|
# Disable normalizations for i3-like behavior
|
||||||
|
enable-normalization-flatten-containers = false;
|
||||||
|
enable-normalization-opposite-orientation-for-nested-containers = false;
|
||||||
|
|
||||||
|
mode.main.binding = {
|
||||||
|
"${cfg.leader}-w" = "layout accordion horizontal"; # tabbed
|
||||||
|
"${cfg.leader}-s" = "layout accordion vertical"; # stacking
|
||||||
|
"${cfg.leader}-e" = "layout tiles horizontal vertical"; # tiles, toggles orientation
|
||||||
|
"${cfg.leader}-shift-q" = "close";
|
||||||
|
"${cfg.leader}-shift-f" = "fullscreen";
|
||||||
|
"${cfg.leader}-h" = "focus left";
|
||||||
|
"${cfg.leader}-j" = "focus down";
|
||||||
|
"${cfg.leader}-k" = "focus up";
|
||||||
|
"${cfg.leader}-l" = "focus right";
|
||||||
|
"${cfg.leader}-shift-h" = "move left";
|
||||||
|
"${cfg.leader}-shift-j" = "move down";
|
||||||
|
"${cfg.leader}-shift-k" = "move up";
|
||||||
|
"${cfg.leader}-shift-l" = "move right";
|
||||||
|
"${cfg.leader}-r" = "mode resize";
|
||||||
|
"${cfg.leader}-1" = "workspace 1";
|
||||||
|
"${cfg.leader}-2" = "workspace 2";
|
||||||
|
"${cfg.leader}-3" = "workspace 3";
|
||||||
|
"${cfg.leader}-4" = "workspace 4";
|
||||||
|
"${cfg.leader}-5" = "workspace 5";
|
||||||
|
"${cfg.leader}-6" = "workspace 6";
|
||||||
|
"${cfg.leader}-7" = "workspace 7";
|
||||||
|
"${cfg.leader}-8" = "workspace 8";
|
||||||
|
"${cfg.leader}-9" = "workspace 9";
|
||||||
|
"${cfg.leader}-0" = "workspace 10";
|
||||||
|
"${cfg.leader}-shift-1" = "move-node-to-workspace 1";
|
||||||
|
"${cfg.leader}-shift-2" = "move-node-to-workspace 2";
|
||||||
|
"${cfg.leader}-shift-3" = "move-node-to-workspace 3";
|
||||||
|
"${cfg.leader}-shift-4" = "move-node-to-workspace 4";
|
||||||
|
"${cfg.leader}-shift-5" = "move-node-to-workspace 5";
|
||||||
|
"${cfg.leader}-shift-6" = "move-node-to-workspace 6";
|
||||||
|
"${cfg.leader}-shift-7" = "move-node-to-workspace 7";
|
||||||
|
"${cfg.leader}-shift-8" = "move-node-to-workspace 8";
|
||||||
|
"${cfg.leader}-shift-9" = "move-node-to-workspace 9";
|
||||||
|
"${cfg.leader}-shift-0" = "move-node-to-workspace 10";
|
||||||
|
"${cfg.leader}-tab" = "workspace-back-and-forth";
|
||||||
|
"${cfg.leader}-shift-tab" = "move-workspace-to-monitor --wrap-around next";
|
||||||
|
|
||||||
|
"${cfg.leader}-enter" = ''
|
||||||
|
exec-and-forget osascript <<'APPLESCRIPT'
|
||||||
|
tell application "Ghostty"
|
||||||
|
activate
|
||||||
|
tell application "System Events"
|
||||||
|
keystroke "n" using {command down}
|
||||||
|
end tell
|
||||||
|
end tell
|
||||||
|
APPLESCRIPT
|
||||||
|
'';
|
||||||
|
|
||||||
|
"${cfg.leader}-shift-enter" = ''
|
||||||
|
exec-and-forget osascript <<'APPLESCRIPT'
|
||||||
|
tell application "Google Chrome"
|
||||||
|
set newWindow to make new window
|
||||||
|
activate
|
||||||
|
tell newWindow to set index to 1
|
||||||
|
end tell
|
||||||
|
APPLESCRIPT
|
||||||
|
'';
|
||||||
|
|
||||||
|
"${cfg.leader}-shift-e" = "exec-and-forget zsh --login -c \"emacsclient -c -n\"";
|
||||||
|
|
||||||
|
# Service mode: Deliberate aerospace window management
|
||||||
|
"${cfg.leader}-i" = "mode service";
|
||||||
|
|
||||||
|
# Passthrough mode: Temporarily disable aerospace to use macOS shortcuts
|
||||||
|
"${cfg.leader}-p" = "mode passthrough";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Resize mode: For window resizing operations
|
||||||
|
mode.resize.binding = {
|
||||||
|
h = "resize width -50";
|
||||||
|
j = "resize height +50";
|
||||||
|
k = "resize height -50";
|
||||||
|
l = "resize width +50";
|
||||||
|
|
||||||
|
minus = "resize smart -50";
|
||||||
|
equal = "resize smart +50";
|
||||||
|
|
||||||
|
esc = "mode main";
|
||||||
|
enter = "mode main";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Service mode: For deliberate aerospace window management operations
|
||||||
|
mode.service.binding = {
|
||||||
|
esc = ["reload-config" "mode main"];
|
||||||
|
r = ["flatten-workspace-tree" "mode main"]; # reset layout
|
||||||
|
f = ["layout floating tiling" "mode main"]; # Toggle between floating and tiling layout
|
||||||
|
backspace = ["close-all-windows-but-current" "mode main"];
|
||||||
|
|
||||||
|
"${cfg.leader}-shift-h" = ["join-with left" "mode main"];
|
||||||
|
"${cfg.leader}-shift-j" = ["join-with down" "mode main"];
|
||||||
|
"${cfg.leader}-shift-k" = ["join-with up" "mode main"];
|
||||||
|
"${cfg.leader}-shift-l" = ["join-with right" "mode main"];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Passthrough mode: All shortcuts pass through to macOS
|
||||||
|
mode.passthrough.binding = {
|
||||||
|
esc = "mode main";
|
||||||
|
"${cfg.leader}-p" = "mode main";
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar integration - notify bar of workspace changes
|
||||||
|
exec-on-workspace-change = mkIf cfg.sketchybar.enable [
|
||||||
|
"/bin/bash" "-c"
|
||||||
|
"${pkgs.sketchybar}/bin/sketchybar --trigger aerospace_workspace_change FOCUSED=$AEROSPACE_FOCUSED_WORKSPACE PREV=$AEROSPACE_PREV_WORKSPACE"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
# Gaps configuration - prevent windows from overlapping SketchyBar
|
||||||
|
(mkIf cfg.sketchybar.enable {
|
||||||
|
gaps = {
|
||||||
|
outer = {
|
||||||
|
top = 0;
|
||||||
|
bottom = 40;
|
||||||
|
left = 0;
|
||||||
|
right = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
cfg.userSettings
|
||||||
|
];
|
||||||
|
|
||||||
|
# Launchd agent for autoraise
|
||||||
|
launchd.agents.autoraise = mkIf cfg.autoraise.enable {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
ProgramArguments = [
|
||||||
|
"${pkgs.autoraise}/bin/AutoRaise"
|
||||||
|
"-pollMillis" (toString cfg.autoraise.pollMillis)
|
||||||
|
"-delay" (toString cfg.autoraise.delay)
|
||||||
|
"-focusDelay" (toString cfg.autoraise.focusDelay)
|
||||||
|
];
|
||||||
|
RunAtLoad = true;
|
||||||
|
KeepAlive = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar configuration
|
||||||
|
home.file.".config/sketchybar/sketchybarrc" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
onChange = "${pkgs.sketchybar}/bin/sketchybar --reload";
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Plugin directory
|
||||||
|
PLUGIN_DIR="$HOME/.config/sketchybar/plugins"
|
||||||
|
|
||||||
|
# Colors - i3/sway theme with exact color matching
|
||||||
|
# Focused window/workspace color from i3/sway
|
||||||
|
FOCUSED=0xff285577
|
||||||
|
|
||||||
|
# Background colors matching i3blocks bar
|
||||||
|
BAR_BG=0xcc000000 # Semi-transparent black
|
||||||
|
ITEM_BG=0xff333333 # Dark gray for inactive items
|
||||||
|
|
||||||
|
# Text colors
|
||||||
|
TEXT=0xffffffff # White text
|
||||||
|
GRAY=0xff888888 # Muted text for inactive items
|
||||||
|
|
||||||
|
# Accent colors for warnings
|
||||||
|
WARNING=0xffff9900
|
||||||
|
CRITICAL=0xff900000
|
||||||
|
|
||||||
|
# Configure the bar appearance
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --bar \
|
||||||
|
position=bottom \
|
||||||
|
height=32 \
|
||||||
|
color=$BAR_BG \
|
||||||
|
border_width=0 \
|
||||||
|
corner_radius=0 \
|
||||||
|
padding_left=10 \
|
||||||
|
padding_right=10
|
||||||
|
|
||||||
|
# Set default properties for all items
|
||||||
|
# Using monospace font to match waybar's Fira Code styling
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --default \
|
||||||
|
updates=when_shown \
|
||||||
|
icon.font="SF Mono:Regular:13.0" \
|
||||||
|
icon.color=$TEXT \
|
||||||
|
icon.padding_left=4 \
|
||||||
|
icon.padding_right=4 \
|
||||||
|
label.font="SF Mono:Regular:13.0" \
|
||||||
|
label.color=$TEXT \
|
||||||
|
label.padding_left=4 \
|
||||||
|
label.padding_right=4 \
|
||||||
|
padding_left=4 \
|
||||||
|
padding_right=4 \
|
||||||
|
background.corner_radius=5 \
|
||||||
|
background.height=24
|
||||||
|
|
||||||
|
# Register aerospace workspace change event
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add event aerospace_workspace_change
|
||||||
|
|
||||||
|
# Create workspace indicators for workspaces 1-10
|
||||||
|
for sid in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
# Display "0" for workspace 10
|
||||||
|
if [ "$sid" = "10" ]; then
|
||||||
|
display="0"
|
||||||
|
else
|
||||||
|
display="$sid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item space.$sid left \
|
||||||
|
--subscribe space.$sid aerospace_workspace_change \
|
||||||
|
--set space.$sid \
|
||||||
|
update_freq=2 \
|
||||||
|
width=32 \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.corner_radius=5 \
|
||||||
|
background.height=20 \
|
||||||
|
background.drawing=on \
|
||||||
|
icon="$display" \
|
||||||
|
icon.padding_left=13 \
|
||||||
|
icon.padding_right=11 \
|
||||||
|
icon.align=center \
|
||||||
|
label.drawing=off \
|
||||||
|
click_script="${pkgs.aerospace}/bin/aerospace workspace $sid" \
|
||||||
|
script="$PLUGIN_DIR/aerospace.sh $sid"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Separator after workspaces
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item separator_left left \
|
||||||
|
--set separator_left \
|
||||||
|
icon="" \
|
||||||
|
label="" \
|
||||||
|
background.drawing=off \
|
||||||
|
padding_left=10 \
|
||||||
|
padding_right=10
|
||||||
|
|
||||||
|
# System monitoring modules (right side)
|
||||||
|
# Note: Items added to 'right' appear in reverse order (last added = leftmost)
|
||||||
|
# Adding in reverse to get: disk | cpu | memory | battery | volume | calendar
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item calendar right \
|
||||||
|
--set calendar \
|
||||||
|
icon="📅" \
|
||||||
|
update_freq=30 \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/calendar.sh"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item separator_media right \
|
||||||
|
--set separator_media \
|
||||||
|
icon="|" \
|
||||||
|
label="" \
|
||||||
|
background.drawing=off \
|
||||||
|
padding_left=5 \
|
||||||
|
padding_right=5
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item volume right \
|
||||||
|
--set volume \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/volume.sh" \
|
||||||
|
--subscribe volume volume_change
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item battery right \
|
||||||
|
--set battery \
|
||||||
|
update_freq=120 \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/battery.sh" \
|
||||||
|
--subscribe battery system_woke power_source_change
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item separator_sys right \
|
||||||
|
--set separator_sys \
|
||||||
|
icon="|" \
|
||||||
|
label="" \
|
||||||
|
background.drawing=off \
|
||||||
|
padding_left=5 \
|
||||||
|
padding_right=5
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item memory right \
|
||||||
|
--set memory \
|
||||||
|
update_freq=5 \
|
||||||
|
icon="🐏" \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/memory.sh"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item cpu right \
|
||||||
|
--set cpu \
|
||||||
|
update_freq=2 \
|
||||||
|
icon="🧠" \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/cpu.sh"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item disk right \
|
||||||
|
--set disk \
|
||||||
|
update_freq=60 \
|
||||||
|
icon="💾" \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/disk.sh"
|
||||||
|
|
||||||
|
# Menu bar extras / system tray items (rightmost)
|
||||||
|
# Note: Requires Screen Recording permission for SketchyBar in System Settings
|
||||||
|
# Use 'sketchybar --query default_menu_items' to discover available items
|
||||||
|
|
||||||
|
# Bluetooth
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,Bluetooth" right \
|
||||||
|
--set "Control Center,Bluetooth" \
|
||||||
|
alias.update_freq=1 \
|
||||||
|
padding_left=0 \
|
||||||
|
padding_right=0
|
||||||
|
|
||||||
|
# WiFi
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,WiFi" right \
|
||||||
|
--set "Control Center,WiFi" \
|
||||||
|
alias.update_freq=1 \
|
||||||
|
padding_left=0 \
|
||||||
|
padding_right=0
|
||||||
|
|
||||||
|
# Add other menu bar apps as discovered
|
||||||
|
# Common examples:
|
||||||
|
# - Cloudflare WARP: --add alias "Cloudflare WARP,Item-0" right
|
||||||
|
# - Notion Calendar: --add alias "Notion Calendar,Item-0" right
|
||||||
|
# Run 'sketchybar --query default_menu_items' to find exact names
|
||||||
|
|
||||||
|
# Update the bar
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --update
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar aerospace workspace plugin
|
||||||
|
home.file.".config/sketchybar/plugins/aerospace.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
FOCUSED_COLOR=0xff285577
|
||||||
|
ITEM_BG=0xff333333
|
||||||
|
TEXT=0xffffffff
|
||||||
|
GRAY=0xff555555
|
||||||
|
|
||||||
|
# Get the currently focused workspace directly from aerospace
|
||||||
|
# Trim whitespace to ensure clean comparison
|
||||||
|
FOCUSED=$(${pkgs.aerospace}/bin/aerospace list-workspaces --focused | tr -d ' \n\r')
|
||||||
|
|
||||||
|
# Get list of empty workspaces
|
||||||
|
EMPTY_WORKSPACES=$(${pkgs.aerospace}/bin/aerospace list-workspaces --monitor all --empty)
|
||||||
|
|
||||||
|
# Clean up the workspace number parameter
|
||||||
|
WORKSPACE_NUM=$(echo "$1" | tr -d ' \n\r')
|
||||||
|
|
||||||
|
# Check if workspace has windows (is NOT empty)
|
||||||
|
IS_EMPTY=false
|
||||||
|
if echo "$EMPTY_WORKSPACES" | grep -q "^$WORKSPACE_NUM$"; then
|
||||||
|
IS_EMPTY=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if this workspace is focused
|
||||||
|
IS_FOCUSED=false
|
||||||
|
if [ "$WORKSPACE_NUM" = "$FOCUSED" ]; then
|
||||||
|
IS_FOCUSED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine visibility and styling
|
||||||
|
# Always show focused workspace (even if empty) with fixed width
|
||||||
|
# Hide non-focused empty workspaces by setting width to 0 (collapsed)
|
||||||
|
# Show non-focused non-empty workspaces with fixed width and inactive styling
|
||||||
|
|
||||||
|
if [ "$IS_FOCUSED" = "true" ]; then
|
||||||
|
# Focused workspace - always show with focused styling
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||||
|
drawing=on \
|
||||||
|
width=32 \
|
||||||
|
icon.padding_left=13 \
|
||||||
|
icon.padding_right=11 \
|
||||||
|
icon.align=center \
|
||||||
|
background.color=$FOCUSED_COLOR \
|
||||||
|
background.drawing=on \
|
||||||
|
icon.color=$TEXT
|
||||||
|
elif [ "$IS_EMPTY" = "true" ]; then
|
||||||
|
# Empty workspace (not focused) - hide by turning off drawing
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||||
|
drawing=off
|
||||||
|
else
|
||||||
|
# Non-empty workspace (not focused) - show with inactive styling
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||||
|
drawing=on \
|
||||||
|
width=32 \
|
||||||
|
icon.padding_left=13 \
|
||||||
|
icon.padding_right=11 \
|
||||||
|
icon.align=center \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
icon.color=$GRAY
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar CPU monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/cpu.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CORE_COUNT=$(sysctl -n machdep.cpu.thread_count)
|
||||||
|
CPU_INFO=$(ps -eo pcpu,user)
|
||||||
|
CPU_SYS=$(echo "$CPU_INFO" | grep -v $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}")
|
||||||
|
CPU_USER=$(echo "$CPU_INFO" | grep $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}")
|
||||||
|
CPU_PERCENT="$(echo "$CPU_SYS $CPU_USER" | awk '{printf "%.0f\n", ($1 + $2)*100}')"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$CPU_PERCENT%"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar memory monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/memory.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
MEMORY_STATS=$(vm_stat)
|
||||||
|
PAGES_FREE=$(echo "$MEMORY_STATS" | grep "Pages free" | awk '{print $3}' | tr -d '.')
|
||||||
|
PAGES_ACTIVE=$(echo "$MEMORY_STATS" | grep "Pages active" | awk '{print $3}' | tr -d '.')
|
||||||
|
PAGES_INACTIVE=$(echo "$MEMORY_STATS" | grep "Pages inactive" | awk '{print $3}' | tr -d '.')
|
||||||
|
PAGES_WIRED=$(echo "$MEMORY_STATS" | grep "Pages wired down" | awk '{print $4}' | tr -d '.')
|
||||||
|
PAGES_COMPRESSED=$(echo "$MEMORY_STATS" | grep "Pages stored in compressor" | awk '{print $5}' | tr -d '.')
|
||||||
|
|
||||||
|
TOTAL_PAGES=$((PAGES_FREE + PAGES_ACTIVE + PAGES_INACTIVE + PAGES_WIRED + PAGES_COMPRESSED))
|
||||||
|
USED_PAGES=$((PAGES_ACTIVE + PAGES_INACTIVE + PAGES_WIRED + PAGES_COMPRESSED))
|
||||||
|
MEMORY_PERCENT=$((USED_PAGES * 100 / TOTAL_PAGES))
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$MEMORY_PERCENT%"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar disk monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/disk.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DISK_USAGE=$(df -H / | grep -v Filesystem | awk '{print $5}')
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$DISK_USAGE"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar battery monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/battery.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PERCENTAGE=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1)
|
||||||
|
CHARGING=$(pmset -g batt | grep 'AC Power')
|
||||||
|
|
||||||
|
if [ "$PERCENTAGE" = "" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Select icon based on battery level
|
||||||
|
case ''${PERCENTAGE} in
|
||||||
|
9[0-9]|100) ICON="🔋"
|
||||||
|
;;
|
||||||
|
[6-8][0-9]) ICON="🔋"
|
||||||
|
;;
|
||||||
|
[3-5][0-9]) ICON="🔋"
|
||||||
|
;;
|
||||||
|
[1-2][0-9]) ICON="🔋"
|
||||||
|
;;
|
||||||
|
*) ICON="🪫"
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Show charging icon if connected to power
|
||||||
|
if [[ $CHARGING != "" ]]; then
|
||||||
|
ICON="⚡"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="''${PERCENTAGE}%"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar volume monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/volume.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ "$SENDER" = "volume_change" ]; then
|
||||||
|
VOLUME=$(osascript -e "output volume of (get volume settings)")
|
||||||
|
MUTED=$(osascript -e "output muted of (get volume settings)")
|
||||||
|
|
||||||
|
if [ "$MUTED" = "true" ]; then
|
||||||
|
ICON="🔇"
|
||||||
|
LABEL=""
|
||||||
|
else
|
||||||
|
case $VOLUME in
|
||||||
|
[6-9][0-9]|100) ICON="🔊"
|
||||||
|
;;
|
||||||
|
[3-5][0-9]) ICON="🔉"
|
||||||
|
;;
|
||||||
|
*) ICON="🔈"
|
||||||
|
esac
|
||||||
|
LABEL="$VOLUME%"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="$LABEL"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar calendar/clock plugin
|
||||||
|
home.file.".config/sketchybar/plugins/calendar.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$(date '+%Y-%m-%d %H:%M')"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Launchd agent for auto-starting sketchybar
|
||||||
|
launchd.agents.sketchybar = mkIf cfg.sketchybar.enable {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
ProgramArguments = [ "${pkgs.sketchybar}/bin/sketchybar" ];
|
||||||
|
RunAtLoad = true;
|
||||||
|
KeepAlive = true;
|
||||||
|
StandardOutPath = "/tmp/sketchybar.log";
|
||||||
|
StandardErrorPath = "/tmp/sketchybar.err.log";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
7
home/roles/base-darwin/default.nix
Normal file
7
home/roles/base-darwin/default.nix
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
# Base imports for Darwin home configurations
|
||||||
|
# Includes Darwin-specific roles that only work on macOS
|
||||||
|
imports = [
|
||||||
|
../aerospace
|
||||||
|
];
|
||||||
|
}
|
||||||
8
home/roles/base-linux/default.nix
Normal file
8
home/roles/base-linux/default.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
# Base imports for Linux home configurations
|
||||||
|
# Includes Linux-specific roles that require Linux-only home-manager modules
|
||||||
|
imports = [
|
||||||
|
../plasma-manager
|
||||||
|
../i3+sway
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -58,11 +58,11 @@ in
|
|||||||
|
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
addKeysToAgent = "yes";
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
"nucdeb1" = {
|
"nucdeb1" = {
|
||||||
hostname = "nucdeb1.oglehome";
|
hostname = "nucdeb1.oglehome";
|
||||||
user = "root";
|
user = "root";
|
||||||
addKeysToAgent = "yes";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ in
|
|||||||
home.packages = [
|
home.packages = [
|
||||||
# Communication apps
|
# Communication apps
|
||||||
pkgs.element-desktop
|
pkgs.element-desktop
|
||||||
|
# Re-enabled in 25.11 after security issues were resolved
|
||||||
pkgs.fluffychat
|
pkgs.fluffychat
|
||||||
pkgs.nextcloud-talk-desktop
|
pkgs.nextcloud-talk-desktop
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
# Shared roles that work across all platforms (Linux, Darwin, etc.)
|
||||||
|
# Platform-specific roles are imported via base-linux or base-darwin
|
||||||
|
# in each home configuration file
|
||||||
imports = [
|
imports = [
|
||||||
./base
|
./base
|
||||||
./communication
|
./communication
|
||||||
@@ -6,8 +9,12 @@
|
|||||||
./development
|
./development
|
||||||
./gaming
|
./gaming
|
||||||
./kdeconnect
|
./kdeconnect
|
||||||
|
./kubectl
|
||||||
|
./launchers
|
||||||
./media
|
./media
|
||||||
./office
|
./office
|
||||||
./sync
|
./sync
|
||||||
|
./tmux
|
||||||
|
./emacs
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ in
|
|||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
# Desktop applications
|
# Desktop applications
|
||||||
bitwarden
|
bitwarden-desktop
|
||||||
dunst
|
dunst
|
||||||
keepassxc
|
keepassxc
|
||||||
kitty
|
unstable.ghostty
|
||||||
|
|
||||||
# Desktop utilities
|
# Desktop utilities
|
||||||
|
feh # Image viewer and wallpaper setter for X11
|
||||||
|
rofi # Application launcher for X11
|
||||||
solaar # Logitech management software
|
solaar # Logitech management software
|
||||||
waybar
|
waybar
|
||||||
wofi
|
wofi # Application launcher for Wayland
|
||||||
|
xdg-utils # XDG utilities for opening files/URLs with default applications
|
||||||
|
|
||||||
# System utilities with GUI components
|
# System utilities with GUI components
|
||||||
(snapcast.override { pulseaudioSupport = true; })
|
(snapcast.override { pulseaudioSupport = true; })
|
||||||
@@ -37,6 +40,14 @@ in
|
|||||||
kdePackages.kaddressbook
|
kdePackages.kaddressbook
|
||||||
kdePackages.kontact
|
kdePackages.kontact
|
||||||
|
|
||||||
|
# KDE System components needed for proper integration
|
||||||
|
kdePackages.kded
|
||||||
|
kdePackages.systemsettings
|
||||||
|
kdePackages.kmenuedit
|
||||||
|
|
||||||
|
# Desktop menu support
|
||||||
|
kdePackages.plasma-desktop # Contains applications.menu
|
||||||
|
|
||||||
# KDE Online Accounts support
|
# KDE Online Accounts support
|
||||||
kdePackages.kaccounts-integration
|
kdePackages.kaccounts-integration
|
||||||
kdePackages.kaccounts-providers
|
kdePackages.kaccounts-providers
|
||||||
@@ -70,8 +81,80 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
xdg.enable = true;
|
# KDE environment variables for proper integration
|
||||||
|
home.sessionVariables = {
|
||||||
|
QT_QPA_PLATFORMTHEME = "kde";
|
||||||
|
KDE_SESSION_VERSION = "6";
|
||||||
|
};
|
||||||
|
|
||||||
|
xdg = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# Ensure desktop files are made available for discovery
|
||||||
|
desktopEntries = {}; # This creates the desktop files directory structure
|
||||||
|
|
||||||
|
mimeApps = {
|
||||||
|
enable = true;
|
||||||
|
associations.added = {
|
||||||
|
# Ensure associations are properly registered
|
||||||
|
"text/html" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/http" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/https" = "firefox.desktop";
|
||||||
|
};
|
||||||
|
defaultApplications = {
|
||||||
|
# Web browsers
|
||||||
|
"text/html" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/http" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/https" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/about" = "firefox.desktop";
|
||||||
|
"x-scheme-handler/unknown" = "firefox.desktop";
|
||||||
|
|
||||||
|
# Documents
|
||||||
|
"application/pdf" = "okular.desktop";
|
||||||
|
"text/plain" = "kate.desktop";
|
||||||
|
"text/x-tex" = "kate.desktop";
|
||||||
|
"text/x-c" = "kate.desktop";
|
||||||
|
"text/x-python" = "kate.desktop";
|
||||||
|
"application/x-shellscript" = "kate.desktop";
|
||||||
|
|
||||||
|
# Images
|
||||||
|
"image/png" = "gwenview.desktop";
|
||||||
|
"image/jpeg" = "gwenview.desktop";
|
||||||
|
"image/jpg" = "gwenview.desktop";
|
||||||
|
"image/gif" = "gwenview.desktop";
|
||||||
|
"image/bmp" = "gwenview.desktop";
|
||||||
|
"image/tiff" = "gwenview.desktop";
|
||||||
|
"image/webp" = "gwenview.desktop";
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
"application/zip" = "ark.desktop";
|
||||||
|
"application/x-tar" = "ark.desktop";
|
||||||
|
"application/x-compressed-tar" = "ark.desktop";
|
||||||
|
"application/x-7z-compressed" = "ark.desktop";
|
||||||
|
"application/x-rar" = "ark.desktop";
|
||||||
|
|
||||||
|
# Audio
|
||||||
|
"audio/mpeg" = "elisa.desktop";
|
||||||
|
"audio/mp4" = "elisa.desktop";
|
||||||
|
"audio/flac" = "elisa.desktop";
|
||||||
|
"audio/ogg" = "elisa.desktop";
|
||||||
|
"audio/wav" = "elisa.desktop";
|
||||||
|
|
||||||
|
# Email
|
||||||
|
"message/rfc822" = "kmail.desktop";
|
||||||
|
"x-scheme-handler/mailto" = "kmail.desktop";
|
||||||
|
|
||||||
|
# Calendar
|
||||||
|
"text/calendar" = "korganizer.desktop";
|
||||||
|
"application/x-vnd.akonadi.calendar.event" = "korganizer.desktop";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Fix for KDE applications.menu file issue on Plasma 6
|
||||||
|
# KDE still looks for applications.menu but Plasma 6 renamed it to plasma-applications.menu
|
||||||
|
xdg.configFile."menus/applications.menu".source = "${pkgs.kdePackages.plasma-workspace}/etc/xdg/menus/plasma-applications.menu";
|
||||||
|
|
||||||
# Note: modules must be imported at top-level home config
|
# Note: modules must be imported at top-level home config
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,93 @@
|
|||||||
{ config, lib, pkgs, customPkgs, globalInputs, system, ... }:
|
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.home.roles.development;
|
cfg = config.home.roles.development;
|
||||||
|
|
||||||
|
# Fetch the claude-plugins repository
|
||||||
|
# Update the rev to get newer versions of the commands
|
||||||
|
claudePluginsRepo = builtins.fetchGit {
|
||||||
|
url = "https://github.com/jeffh/claude-plugins.git";
|
||||||
|
# To update: change this to the latest commit hash
|
||||||
|
# You can find the latest commit at: https://github.com/jeffh/claude-plugins/commits/main
|
||||||
|
rev = "5e3e4d937162185b6d78c62022cbfd1c8ad42c4c";
|
||||||
|
ref = "main";
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.home.roles.development = {
|
options.home.roles.development = {
|
||||||
enable = mkEnableOption "Enable development tools and utilities";
|
enable = mkEnableOption "Enable development tools and utilities";
|
||||||
|
|
||||||
|
allowArbitraryClaudeCodeModelSelection = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to preserve model specifications in Claude Code humanlayer commands and agents.
|
||||||
|
|
||||||
|
When false (default), the model: line is stripped from frontmatter, allowing Claude Code
|
||||||
|
to use its default model selection.
|
||||||
|
|
||||||
|
When true, the model: specifications from the source files are preserved, allowing
|
||||||
|
commands to specify opus/sonnet/haiku explicitly.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.packages = [
|
home.packages = [
|
||||||
pkgs.claude-code
|
pkgs.unstable.claude-code
|
||||||
pkgs.codex
|
pkgs.unstable.claude-code-router
|
||||||
pkgs.goose-cli
|
pkgs.unstable.codex
|
||||||
|
|
||||||
# Custom packages
|
# Custom packages
|
||||||
customPkgs.tea-rbw
|
pkgs.custom.tea-rbw
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.kubectl-secure.enable = true;
|
# Install Claude Code humanlayer command and agent plugins
|
||||||
|
home.activation.claudeCodeCommands = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
|
# Clean up old plugin-installed commands and agents to avoid duplicates
|
||||||
|
rm -f ~/.claude/commands/humanlayer:* 2>/dev/null || true
|
||||||
|
rm -f ~/.claude/agents/humanlayer:* 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create directories if they don't exist
|
||||||
|
mkdir -p ~/.claude/commands
|
||||||
|
mkdir -p ~/.claude/agents
|
||||||
|
|
||||||
|
# Copy all humanlayer command files and remove model specifications
|
||||||
|
for file in ${claudePluginsRepo}/humanlayer/commands/*.md; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
filename=$(basename "$file" .md)
|
||||||
|
dest="$HOME/.claude/commands/humanlayer:''${filename}.md"
|
||||||
|
|
||||||
|
# Copy file and conditionally remove the "model:" line from frontmatter
|
||||||
|
${if cfg.allowArbitraryClaudeCodeModelSelection
|
||||||
|
then "cp \"$file\" \"$dest\""
|
||||||
|
else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\""
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Copy all humanlayer agent files and remove model specifications
|
||||||
|
for file in ${claudePluginsRepo}/humanlayer/agents/*.md; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
filename=$(basename "$file" .md)
|
||||||
|
dest="$HOME/.claude/agents/humanlayer:''${filename}.md"
|
||||||
|
|
||||||
|
# Copy file and conditionally remove the "model:" line from frontmatter
|
||||||
|
${if cfg.allowArbitraryClaudeCodeModelSelection
|
||||||
|
then "cp \"$file\" \"$dest\""
|
||||||
|
else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\""
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
$DRY_RUN_CMD echo "Claude Code humanlayer commands and agents installed successfully${
|
||||||
|
if cfg.allowArbitraryClaudeCodeModelSelection
|
||||||
|
then " (model specifications preserved)"
|
||||||
|
else " (model selection removed)"
|
||||||
|
}"
|
||||||
|
'';
|
||||||
|
|
||||||
# Note: modules must be imported at top-level home config
|
# Note: modules must be imported at top-level home config
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
cfg = config.home.roles.emacs;
|
||||||
|
|
||||||
doomEmacs = pkgs.fetchFromGitHub {
|
doomEmacs = pkgs.fetchFromGitHub {
|
||||||
owner = "doomemacs";
|
owner = "doomemacs";
|
||||||
repo = "doomemacs";
|
repo = "doomemacs";
|
||||||
@@ -17,20 +19,23 @@ let
|
|||||||
];
|
];
|
||||||
|
|
||||||
# Default emacs configuration with vterm support
|
# Default emacs configuration with vterm support
|
||||||
defaultEmacsPackage =
|
defaultEmacsPackage =
|
||||||
if pkgs.stdenv.isDarwin
|
if pkgs.stdenv.isDarwin
|
||||||
then pkgs.emacs-macport.pkgs.withPackages emacsPackages
|
then pkgs.emacs-macport.pkgs.withPackages emacsPackages
|
||||||
else pkgs.emacs.pkgs.withPackages emacsPackages;
|
else pkgs.emacs.pkgs.withPackages emacsPackages;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = {
|
options.home.roles.emacs = {
|
||||||
|
enable = mkEnableOption "Doom Emacs with vterm and tree-sitter support";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
home.packages = [
|
home.packages = [
|
||||||
pkgs.emacs-all-the-icons-fonts
|
pkgs.emacs-all-the-icons-fonts
|
||||||
pkgs.fira-code
|
pkgs.fira-code
|
||||||
pkgs.fontconfig
|
pkgs.fontconfig
|
||||||
pkgs.graphviz
|
pkgs.graphviz
|
||||||
pkgs.isort
|
pkgs.isort
|
||||||
#pkgs.libvterm # native vterm library
|
|
||||||
pkgs.nerd-fonts.fira-code
|
pkgs.nerd-fonts.fira-code
|
||||||
pkgs.nerd-fonts.droid-sans-mono
|
pkgs.nerd-fonts.droid-sans-mono
|
||||||
pkgs.nil # nix lsp language server
|
pkgs.nil # nix lsp language server
|
||||||
@@ -66,7 +71,7 @@ in
|
|||||||
home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
# Always remove and recreate the symlink to ensure it points to the source directory
|
# Always remove and recreate the symlink to ensure it points to the source directory
|
||||||
rm -rf "${config.xdg.configHome}/doom"
|
rm -rf "${config.xdg.configHome}/doom"
|
||||||
ln -sf "${config.home.homeDirectory}/nixos-configs/home/modules/emacs/doom" "${config.xdg.configHome}/doom"
|
ln -sf "${config.home.homeDirectory}/nixos-configs/home/roles/emacs/doom" "${config.xdg.configHome}/doom"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
470
home/roles/i3+sway/default.nix
Normal file
470
home/roles/i3+sway/default.nix
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.i3_sway;
|
||||||
|
|
||||||
|
shared_config = recursiveUpdate rec {
|
||||||
|
modifier = "Mod4";
|
||||||
|
terminal = "ghostty";
|
||||||
|
defaultWorkspace = "workspace number 1";
|
||||||
|
|
||||||
|
keybindings = {
|
||||||
|
"${shared_config.modifier}+Return" = "exec ${terminal}";
|
||||||
|
"${shared_config.modifier}+Shift+q" = "kill";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+a" = "focus parent";
|
||||||
|
"${shared_config.modifier}+Shift+a" = "focus child";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+h" = "focus left";
|
||||||
|
"${shared_config.modifier}+j" = "focus down";
|
||||||
|
"${shared_config.modifier}+k" = "focus up";
|
||||||
|
"${shared_config.modifier}+l" = "focus right";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Shift+h" = "move left";
|
||||||
|
"${shared_config.modifier}+Shift+j" = "move down";
|
||||||
|
"${shared_config.modifier}+Shift+k" = "move up";
|
||||||
|
"${shared_config.modifier}+Shift+l" = "move right";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Left" = "focus left";
|
||||||
|
"${shared_config.modifier}+Down" = "focus down";
|
||||||
|
"${shared_config.modifier}+Up" = "focus up";
|
||||||
|
"${shared_config.modifier}+Right" = "focus right";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Shift+Left" = "move left";
|
||||||
|
"${shared_config.modifier}+Shift+Down" = "move down";
|
||||||
|
"${shared_config.modifier}+Shift+Up" = "move up";
|
||||||
|
"${shared_config.modifier}+Shift+Right" = "move right";
|
||||||
|
|
||||||
|
#"${shared_config.modifier}+h" = "split h";
|
||||||
|
"${shared_config.modifier}+v" = "split v";
|
||||||
|
"${shared_config.modifier}+Shift+f" = "fullscreen toggle";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+s" = "layout stacking";
|
||||||
|
"${shared_config.modifier}+w" = "layout tabbed";
|
||||||
|
"${shared_config.modifier}+e" = "layout toggle split";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Shift+space" = "floating toggle";
|
||||||
|
"${shared_config.modifier}+space" = "focus mode_toggle";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Shift+minus" = "move scratchpad";
|
||||||
|
"${shared_config.modifier}+minus" = "scratchpad show";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+1" = "workspace number 1";
|
||||||
|
"${shared_config.modifier}+2" = "workspace number 2";
|
||||||
|
"${shared_config.modifier}+3" = "workspace number 3";
|
||||||
|
"${shared_config.modifier}+4" = "workspace number 4";
|
||||||
|
"${shared_config.modifier}+5" = "workspace number 5";
|
||||||
|
"${shared_config.modifier}+6" = "workspace number 6";
|
||||||
|
"${shared_config.modifier}+7" = "workspace number 7";
|
||||||
|
"${shared_config.modifier}+8" = "workspace number 8";
|
||||||
|
"${shared_config.modifier}+9" = "workspace number 9";
|
||||||
|
"${shared_config.modifier}+0" = "workspace number 10";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Shift+1" =
|
||||||
|
"move container to workspace number 1";
|
||||||
|
"${shared_config.modifier}+Shift+2" =
|
||||||
|
"move container to workspace number 2";
|
||||||
|
"${shared_config.modifier}+Shift+3" =
|
||||||
|
"move container to workspace number 3";
|
||||||
|
"${shared_config.modifier}+Shift+4" =
|
||||||
|
"move container to workspace number 4";
|
||||||
|
"${shared_config.modifier}+Shift+5" =
|
||||||
|
"move container to workspace number 5";
|
||||||
|
"${shared_config.modifier}+Shift+6" =
|
||||||
|
"move container to workspace number 6";
|
||||||
|
"${shared_config.modifier}+Shift+7" =
|
||||||
|
"move container to workspace number 7";
|
||||||
|
"${shared_config.modifier}+Shift+8" =
|
||||||
|
"move container to workspace number 8";
|
||||||
|
"${shared_config.modifier}+Shift+9" =
|
||||||
|
"move container to workspace number 9";
|
||||||
|
"${shared_config.modifier}+Shift+0" =
|
||||||
|
"move container to workspace number 10";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+Shift+c" = "reload";
|
||||||
|
"${shared_config.modifier}+Shift+r" = "restart";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+r" = "mode resize";
|
||||||
|
|
||||||
|
"XF86MonBrightnessUp" = "exec ddcutil setvcp 10 + 5";
|
||||||
|
"XF86MonBrightnessDown" = "exec ddcutil setvcp 10 - 5";
|
||||||
|
};
|
||||||
|
} cfg.extraSharedConfig;
|
||||||
|
in {
|
||||||
|
options.home.roles.i3_sway = {
|
||||||
|
enable = mkEnableOption "i3 and Sway tiling window managers with waybar and rofi";
|
||||||
|
|
||||||
|
extraSharedConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = "Extra configuration shared between i3 and sway";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraI3Config = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = "Extra i3-specific configuration";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraSwayConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = "Extra sway-specific configuration";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# i3blocks configuration file
|
||||||
|
home.file.".config/i3blocks/config".text = ''
|
||||||
|
# i3blocks config - replicating waybar setup
|
||||||
|
separator_block_width=15
|
||||||
|
markup=pango
|
||||||
|
|
||||||
|
[disk]
|
||||||
|
command=df -h / | awk 'NR==2 {print "💾 " $5}'
|
||||||
|
interval=30
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[cpu]
|
||||||
|
command=top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print "🧠 " int(100 - $1) "%"}'
|
||||||
|
interval=2
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[memory]
|
||||||
|
command=free | awk 'NR==2 {printf "🐏 %.0f%%\n", $3*100/$2}'
|
||||||
|
interval=5
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[pulseaudio]
|
||||||
|
command=${pkgs.writeShellScript "i3blocks-pulseaudio" ''
|
||||||
|
volume=$(pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '\d+%' | head -1)
|
||||||
|
muted=$(pactl get-sink-mute @DEFAULT_SINK@ | grep -o 'yes')
|
||||||
|
if [ "$muted" = "yes" ]; then
|
||||||
|
echo "🔇"
|
||||||
|
else
|
||||||
|
vol_num=''${volume%\%}
|
||||||
|
if [ $vol_num -le 33 ]; then
|
||||||
|
echo "🔈 $volume"
|
||||||
|
elif [ $vol_num -le 66 ]; then
|
||||||
|
echo "🔉 $volume"
|
||||||
|
else
|
||||||
|
echo "🔊 $volume"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
interval=1
|
||||||
|
signal=10
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[backlight]
|
||||||
|
command=${pkgs.writeShellScript "i3blocks-backlight" ''
|
||||||
|
if command -v ddcutil &>/dev/null; then
|
||||||
|
# Handle mouse scroll events
|
||||||
|
case $BLOCK_BUTTON in
|
||||||
|
4) ddcutil setvcp 10 + 5 ;; # Scroll up - increase brightness
|
||||||
|
5) ddcutil setvcp 10 - 5 ;; # Scroll down - decrease brightness
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Display current brightness
|
||||||
|
brightness=$(ddcutil getvcp 10 2>/dev/null | grep -oP 'current value =\s*\K\d+')
|
||||||
|
if [ -n "$brightness" ]; then
|
||||||
|
echo "☀️ $brightness%"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
interval=5
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[network]
|
||||||
|
command=${pkgs.writeShellScript "i3blocks-network" ''
|
||||||
|
if iwgetid -r &>/dev/null; then
|
||||||
|
ssid=$(iwgetid -r)
|
||||||
|
signal=$(grep "^\s*w" /proc/net/wireless | awk '{print int($3 * 100 / 70)}')
|
||||||
|
echo "📶 $ssid ($signal%)"
|
||||||
|
else
|
||||||
|
ip=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||||
|
if [ -n "$ip" ]; then
|
||||||
|
echo "🔌 $ip"
|
||||||
|
else
|
||||||
|
echo "❌"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
interval=5
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[battery]
|
||||||
|
command=${pkgs.writeShellScript "i3blocks-battery" ''
|
||||||
|
if [ -d /sys/class/power_supply/BAT0 ]; then
|
||||||
|
capacity=$(cat /sys/class/power_supply/BAT0/capacity)
|
||||||
|
status=$(cat /sys/class/power_supply/BAT0/status)
|
||||||
|
|
||||||
|
if [ "$status" = "Charging" ]; then
|
||||||
|
echo "⚡ $capacity%"
|
||||||
|
else
|
||||||
|
echo "🔋 $capacity%"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
interval=10
|
||||||
|
separator=true
|
||||||
|
|
||||||
|
[time]
|
||||||
|
command=date '+%Y-%m-%d %H:%M'
|
||||||
|
interval=1
|
||||||
|
separator=false
|
||||||
|
'';
|
||||||
|
|
||||||
|
xsession.windowManager.i3 = let
|
||||||
|
base_i3_config = recursiveUpdate shared_config {
|
||||||
|
bars = [{
|
||||||
|
position = "bottom";
|
||||||
|
statusCommand = "${pkgs.i3blocks}/bin/i3blocks";
|
||||||
|
trayOutput = "primary"; # Enable system tray on primary output
|
||||||
|
fonts = {
|
||||||
|
names = [ "Fira Code" "monospace" ];
|
||||||
|
size = 11.0;
|
||||||
|
};
|
||||||
|
colors = {
|
||||||
|
background = "#000000";
|
||||||
|
statusline = "#ffffff";
|
||||||
|
separator = "#666666";
|
||||||
|
|
||||||
|
# Workspace button colors (matching waybar)
|
||||||
|
focusedWorkspace = {
|
||||||
|
border = "#285577";
|
||||||
|
background = "#285577";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
activeWorkspace = {
|
||||||
|
border = "#5f676a";
|
||||||
|
background = "#5f676a";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
inactiveWorkspace = {
|
||||||
|
border = "#222222";
|
||||||
|
background = "#222222";
|
||||||
|
text = "#888888";
|
||||||
|
};
|
||||||
|
urgentWorkspace = {
|
||||||
|
border = "#900000";
|
||||||
|
background = "#900000";
|
||||||
|
text = "#ffffff";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
keybindings = shared_config.keybindings // {
|
||||||
|
"${shared_config.modifier}+d" = "exec rofi -show drun";
|
||||||
|
"${shared_config.modifier}+Shift+e" =
|
||||||
|
"exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'";
|
||||||
|
};
|
||||||
|
startup = [
|
||||||
|
# GNOME polkit authentication agent
|
||||||
|
{
|
||||||
|
command = "/run/current-system/sw/libexec/polkit-gnome-authentication-agent-1";
|
||||||
|
always = false;
|
||||||
|
notification = false;
|
||||||
|
}
|
||||||
|
# Picom compositor for smooth rendering and no tearing (important for Nvidia)
|
||||||
|
{
|
||||||
|
command = "picom --backend glx -b";
|
||||||
|
always = false;
|
||||||
|
notification = false;
|
||||||
|
}
|
||||||
|
# NetworkManager system tray applet
|
||||||
|
{
|
||||||
|
command = "nm-applet";
|
||||||
|
always = false;
|
||||||
|
notification = false;
|
||||||
|
}
|
||||||
|
# Set wallpaper with feh
|
||||||
|
{
|
||||||
|
command = "feh --bg-scale ${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg}";
|
||||||
|
always = false;
|
||||||
|
notification = false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
enable = true;
|
||||||
|
config = recursiveUpdate base_i3_config cfg.extraI3Config;
|
||||||
|
};
|
||||||
|
|
||||||
|
wayland.windowManager.sway = let
|
||||||
|
base_sway_config = recursiveUpdate shared_config {
|
||||||
|
bars = []; # Disable default bar, use waybar instead
|
||||||
|
keybindings = shared_config.keybindings // {
|
||||||
|
"${shared_config.modifier}+d" = "exec wofi --show drun";
|
||||||
|
"${shared_config.modifier}+Shift+e" =
|
||||||
|
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";
|
||||||
|
};
|
||||||
|
input = {
|
||||||
|
"type:keyboard" = {
|
||||||
|
xkb_options = "caps:escape";
|
||||||
|
};
|
||||||
|
"type:touchpad" = {
|
||||||
|
tap = "enabled";
|
||||||
|
tap_button_map = "lrm";
|
||||||
|
drag = "enabled";
|
||||||
|
natural_scroll = "disabled";
|
||||||
|
dwt = "enabled";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
output = {
|
||||||
|
"*" = {
|
||||||
|
bg = "${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg} fill";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
startup = [
|
||||||
|
# Launch waybar status bar
|
||||||
|
{
|
||||||
|
command = "waybar";
|
||||||
|
always = false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
enable = true;
|
||||||
|
extraOptions = [ "--unsupported-gpu" ];
|
||||||
|
config = recursiveUpdate base_sway_config cfg.extraSwayConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.waybar = {
|
||||||
|
enable = true;
|
||||||
|
systemd.enable = false; # Don't auto-start via systemd - only launch in sway
|
||||||
|
settings = {
|
||||||
|
mainBar = {
|
||||||
|
layer = "top";
|
||||||
|
position = "bottom";
|
||||||
|
height = 30;
|
||||||
|
spacing = 4;
|
||||||
|
|
||||||
|
modules-left = [ "sway/workspaces" "sway/mode" ];
|
||||||
|
modules-center = [ ];
|
||||||
|
modules-right = [ "disk" "cpu" "memory" "pulseaudio" "backlight" "network" "battery" "tray" "clock" ];
|
||||||
|
|
||||||
|
"sway/workspaces" = {
|
||||||
|
disable-scroll = true;
|
||||||
|
all-outputs = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"clock" = {
|
||||||
|
format = "{:%Y-%m-%d %H:%M}";
|
||||||
|
tooltip-format = "<tt><small>{calendar}</small></tt>";
|
||||||
|
calendar = {
|
||||||
|
mode = "year";
|
||||||
|
mode-mon-col = 3;
|
||||||
|
weeks-pos = "right";
|
||||||
|
on-scroll = 1;
|
||||||
|
format = {
|
||||||
|
months = "<span color='#ffead3'><b>{}</b></span>";
|
||||||
|
days = "<span color='#ecc6d9'><b>{}</b></span>";
|
||||||
|
weeks = "<span color='#99ffdd'><b>W{}</b></span>";
|
||||||
|
weekdays = "<span color='#ffcc66'><b>{}</b></span>";
|
||||||
|
today = "<span color='#ff6699'><b><u>{}</u></b></span>";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"disk" = {
|
||||||
|
interval = 30;
|
||||||
|
format = "💾 {percentage_used}%";
|
||||||
|
path = "/";
|
||||||
|
tooltip-format = "Used: {used} / {total} ({percentage_used}%)\nFree: {free} ({percentage_free}%)";
|
||||||
|
};
|
||||||
|
|
||||||
|
"cpu" = {
|
||||||
|
format = "🧠 {usage}%";
|
||||||
|
tooltip = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
"memory" = {
|
||||||
|
format = "🐏 {percentage}%";
|
||||||
|
tooltip-format = "RAM: {used:0.1f}G / {total:0.1f}G";
|
||||||
|
};
|
||||||
|
|
||||||
|
"pulseaudio" = {
|
||||||
|
format = "{icon} {volume}%";
|
||||||
|
format-muted = "🔇";
|
||||||
|
format-icons = {
|
||||||
|
headphone = "🎧";
|
||||||
|
default = [ "🔈" "🔉" "🔊" ];
|
||||||
|
};
|
||||||
|
on-click = "pavucontrol";
|
||||||
|
};
|
||||||
|
|
||||||
|
"backlight" = {
|
||||||
|
format = "☀️ {percent}%";
|
||||||
|
tooltip = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
"network" = {
|
||||||
|
format-wifi = "📶 {essid} ({signalStrength}%)";
|
||||||
|
format-ethernet = "🔌 {ipaddr}";
|
||||||
|
format-disconnected = "❌";
|
||||||
|
tooltip-format = "{ifname}: {ipaddr}/{cidr}";
|
||||||
|
};
|
||||||
|
|
||||||
|
"battery" = {
|
||||||
|
states = {
|
||||||
|
warning = 30;
|
||||||
|
critical = 15;
|
||||||
|
};
|
||||||
|
format = "{icon} {capacity}%";
|
||||||
|
format-charging = "⚡ {capacity}%";
|
||||||
|
format-icons = [ "🪫" "🔋" "🔋" "🔋" "🔋" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"tray" = {
|
||||||
|
spacing = 10;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
style = ''
|
||||||
|
* {
|
||||||
|
padding: 0 4px;
|
||||||
|
font-family: "Fira Code", monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button {
|
||||||
|
padding: 0 8px;
|
||||||
|
background-color: #333333;
|
||||||
|
color: #ffffff;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.focused {
|
||||||
|
background-color: #285577;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.visible {
|
||||||
|
background-color: #5f676a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.urgent {
|
||||||
|
background-color: #900000;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.rofi = {
|
||||||
|
enable = true;
|
||||||
|
theme = "solarized";
|
||||||
|
extraConfig = {
|
||||||
|
modi = "drun,run,window";
|
||||||
|
show-icons = true;
|
||||||
|
drun-display-format = "{name}";
|
||||||
|
disable-history = false;
|
||||||
|
hide-scrollbar = true;
|
||||||
|
display-drun = " Apps";
|
||||||
|
display-run = " Run";
|
||||||
|
display-window = " Windows";
|
||||||
|
sidebar-mode = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.programs.kubectl-secure;
|
cfg = config.home.roles.kubectl;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.programs.kubectl-secure = {
|
options.home.roles.kubectl = {
|
||||||
enable = mkEnableOption "secure kubectl configuration with Bitwarden integration";
|
enable = mkEnableOption "management tools for the homelab k3s oglenet cluster with secure Bitwarden integration";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@@ -21,29 +21,29 @@ in
|
|||||||
programs.bash.initExtra = mkAfter ''
|
programs.bash.initExtra = mkAfter ''
|
||||||
# Kubectl secure session management
|
# Kubectl secure session management
|
||||||
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
|
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
|
||||||
|
|
||||||
kube-select() {
|
kube-select() {
|
||||||
if [[ $# -ne 1 ]]; then
|
if [[ $# -ne 1 ]]; then
|
||||||
echo "Usage: kube-select <context-name>"
|
echo "Usage: kube-select <context-name>"
|
||||||
echo "Available contexts: $(kube-list)"
|
echo "Available contexts: $(kube-list)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local context="$1"
|
local context="$1"
|
||||||
|
|
||||||
# Clean up any existing session first
|
# Clean up any existing session first
|
||||||
kube-clear 2>/dev/null
|
kube-clear 2>/dev/null
|
||||||
|
|
||||||
# Create new session directory
|
# Create new session directory
|
||||||
mkdir -p "$KUBECTL_SESSION_DIR"
|
mkdir -p "$KUBECTL_SESSION_DIR"
|
||||||
chmod 700 "$KUBECTL_SESSION_DIR"
|
chmod 700 "$KUBECTL_SESSION_DIR"
|
||||||
|
|
||||||
# Set cleanup trap for this shell session
|
# Set cleanup trap for this shell session
|
||||||
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
|
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
|
||||||
|
|
||||||
# Set KUBECONFIG for this session
|
# Set KUBECONFIG for this session
|
||||||
export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
|
export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
|
||||||
|
|
||||||
# Load config from Bitwarden secure notes
|
# Load config from Bitwarden secure notes
|
||||||
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
|
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
|
||||||
echo "Error: Could not retrieve kubectl-$context from Bitwarden"
|
echo "Error: Could not retrieve kubectl-$context from Bitwarden"
|
||||||
@@ -51,37 +51,37 @@ in
|
|||||||
kube-clear
|
kube-clear
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify the kubeconfig is valid
|
# Verify the kubeconfig is valid
|
||||||
if ! kubectl config view >/dev/null 2>&1; then
|
if ! kubectl config view >/dev/null 2>&1; then
|
||||||
echo "Error: Invalid kubeconfig retrieved from Bitwarden"
|
echo "Error: Invalid kubeconfig retrieved from Bitwarden"
|
||||||
kube-clear
|
kube-clear
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✓ Loaded kubectl context: $context (session: $$)"
|
echo "✓ Loaded kubectl context: $context (session: $$)"
|
||||||
echo " Config location: $KUBECONFIG"
|
echo " Config location: $KUBECONFIG"
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-list() {
|
kube-list() {
|
||||||
echo "Available kubectl contexts in Bitwarden:"
|
echo "Available kubectl contexts in Bitwarden:"
|
||||||
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
|
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-clear() {
|
kube-clear() {
|
||||||
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
|
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
|
||||||
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
|
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
|
||||||
unset KUBECTL_TIMEOUT_PID
|
unset KUBECTL_TIMEOUT_PID
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
|
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
|
||||||
rm -rf "$KUBECTL_SESSION_DIR"
|
rm -rf "$KUBECTL_SESSION_DIR"
|
||||||
echo "Cleared kubectl session ($$)"
|
echo "Cleared kubectl session ($$)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unset KUBECONFIG
|
unset KUBECONFIG
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-status() {
|
kube-status() {
|
||||||
if [[ -f "$KUBECONFIG" ]]; then
|
if [[ -f "$KUBECONFIG" ]]; then
|
||||||
local current_context
|
local current_context
|
||||||
@@ -89,7 +89,7 @@ in
|
|||||||
if [[ -n "$current_context" ]]; then
|
if [[ -n "$current_context" ]]; then
|
||||||
echo "Active kubectl context: $current_context"
|
echo "Active kubectl context: $current_context"
|
||||||
echo "Session: $$ | Config: $KUBECONFIG"
|
echo "Session: $$ | Config: $KUBECONFIG"
|
||||||
|
|
||||||
# Show cluster info
|
# Show cluster info
|
||||||
local cluster_server
|
local cluster_server
|
||||||
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
|
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
|
||||||
@@ -128,33 +128,33 @@ in
|
|||||||
echo "Note: Kubeconfigs are stored as secure notes in Bitwarden"
|
echo "Note: Kubeconfigs are stored as secure notes in Bitwarden"
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
programs.zsh.initExtra = mkAfter ''
|
programs.zsh.initExtra = mkAfter ''
|
||||||
# Kubectl secure session management (zsh)
|
# Kubectl secure session management (zsh)
|
||||||
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
|
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
|
||||||
|
|
||||||
kube-select() {
|
kube-select() {
|
||||||
if [[ $# -ne 1 ]]; then
|
if [[ $# -ne 1 ]]; then
|
||||||
echo "Usage: kube-select <context-name>"
|
echo "Usage: kube-select <context-name>"
|
||||||
echo "Available contexts: $(kube-list)"
|
echo "Available contexts: $(kube-list)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local context="$1"
|
local context="$1"
|
||||||
|
|
||||||
# Clean up any existing session first
|
# Clean up any existing session first
|
||||||
kube-clear 2>/dev/null
|
kube-clear 2>/dev/null
|
||||||
|
|
||||||
# Create new session directory
|
# Create new session directory
|
||||||
mkdir -p "$KUBECTL_SESSION_DIR"
|
mkdir -p "$KUBECTL_SESSION_DIR"
|
||||||
chmod 700 "$KUBECTL_SESSION_DIR"
|
chmod 700 "$KUBECTL_SESSION_DIR"
|
||||||
|
|
||||||
# Set cleanup trap for this shell session
|
# Set cleanup trap for this shell session
|
||||||
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
|
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
|
||||||
|
|
||||||
# Set KUBECONFIG for this session
|
# Set KUBECONFIG for this session
|
||||||
export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
|
export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
|
||||||
|
|
||||||
# Load config from Bitwarden secure notes
|
# Load config from Bitwarden secure notes
|
||||||
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
|
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
|
||||||
echo "Error: Could not retrieve kubectl-$context from Bitwarden"
|
echo "Error: Could not retrieve kubectl-$context from Bitwarden"
|
||||||
@@ -162,43 +162,37 @@ in
|
|||||||
kube-clear
|
kube-clear
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify the kubeconfig is valid
|
# Verify the kubeconfig is valid
|
||||||
if ! kubectl config view >/dev/null 2>&1; then
|
if ! kubectl config view >/dev/null 2>&1; then
|
||||||
echo "Error: Invalid kubeconfig retrieved from Bitwarden"
|
echo "Error: Invalid kubeconfig retrieved from Bitwarden"
|
||||||
kube-clear
|
kube-clear
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✓ Loaded kubectl context: $context (session: $$)"
|
echo "✓ Loaded kubectl context: $context (session: $$)"
|
||||||
echo " Config location: $KUBECONFIG"
|
echo " Config location: $KUBECONFIG"
|
||||||
|
|
||||||
# Optional: Set timeout cleanup
|
|
||||||
if [[ ${toString cfg.sessionTimeout} -gt 0 ]]; then
|
|
||||||
(sleep ${toString cfg.sessionTimeout}; kube-clear 2>/dev/null) &
|
|
||||||
export KUBECTL_TIMEOUT_PID=$!
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-list() {
|
kube-list() {
|
||||||
echo "Available kubectl contexts in Bitwarden:"
|
echo "Available kubectl contexts in Bitwarden:"
|
||||||
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
|
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-clear() {
|
kube-clear() {
|
||||||
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
|
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
|
||||||
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
|
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
|
||||||
unset KUBECTL_TIMEOUT_PID
|
unset KUBECTL_TIMEOUT_PID
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
|
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
|
||||||
rm -rf "$KUBECTL_SESSION_DIR"
|
rm -rf "$KUBECTL_SESSION_DIR"
|
||||||
echo "Cleared kubectl session ($$)"
|
echo "Cleared kubectl session ($$)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unset KUBECONFIG
|
unset KUBECONFIG
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-status() {
|
kube-status() {
|
||||||
if [[ -f "$KUBECONFIG" ]]; then
|
if [[ -f "$KUBECONFIG" ]]; then
|
||||||
local current_context
|
local current_context
|
||||||
@@ -206,7 +200,7 @@ in
|
|||||||
if [[ -n "$current_context" ]]; then
|
if [[ -n "$current_context" ]]; then
|
||||||
echo "Active kubectl context: $current_context"
|
echo "Active kubectl context: $current_context"
|
||||||
echo "Session: $$ | Config: $KUBECONFIG"
|
echo "Session: $$ | Config: $KUBECONFIG"
|
||||||
|
|
||||||
# Show cluster info
|
# Show cluster info
|
||||||
local cluster_server
|
local cluster_server
|
||||||
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
|
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
|
||||||
36
home/roles/launchers/default.nix
Normal file
36
home/roles/launchers/default.nix
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.launchers;
|
||||||
|
|
||||||
|
# Generate a wrapper script for a package
|
||||||
|
makeLauncher = packageName: pkgs.writeShellScriptBin packageName ''
|
||||||
|
exec env NIXPKGS_ALLOW_UNFREE=1 ${pkgs.nix}/bin/nix run --impure nixpkgs#${packageName} -- "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Generate all launcher scripts from the package list
|
||||||
|
launcherPackages = map makeLauncher cfg.packages;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.launchers = {
|
||||||
|
enable = mkEnableOption "wrapper launchers for excluded packages";
|
||||||
|
|
||||||
|
packages = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
example = [ "steam" "libreoffice" "lutris" ];
|
||||||
|
description = ''
|
||||||
|
List of package names to create launcher wrappers for.
|
||||||
|
Each wrapper will run: NIXPKGS_ALLOW_UNFREE=1 nix run --impure nixpkgs#<package>
|
||||||
|
|
||||||
|
This is useful for occasionally running packages without permanently installing them.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.packages = launcherPackages;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -18,6 +18,10 @@ in
|
|||||||
delfin
|
delfin
|
||||||
moonlight-qt
|
moonlight-qt
|
||||||
vlc
|
vlc
|
||||||
|
|
||||||
|
# Spotify client
|
||||||
|
# Using unstable version for better authentication support
|
||||||
|
unstable.ncspot
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
188
home/roles/plasma-manager/default.nix
Normal file
188
home/roles/plasma-manager/default.nix
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.plasma-manager;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.plasma-manager = {
|
||||||
|
enable = mkEnableOption "KDE Plasma desktop environment configuration";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# The current KDE config can be output with the command:
|
||||||
|
# nix run github:nix-community/plasma-manager
|
||||||
|
#
|
||||||
|
# Plasma-manager options documentation
|
||||||
|
# https://nix-community.github.io/plasma-manager/options.xhtml
|
||||||
|
#
|
||||||
|
# TODO: (ambitious) Add Kmail support to plasma-manager
|
||||||
|
programs.plasma = {
|
||||||
|
enable = true;
|
||||||
|
overrideConfig = true;
|
||||||
|
|
||||||
|
hotkeys.commands."launch-ghostty" = {
|
||||||
|
name = "Launch Ghostty";
|
||||||
|
key = "Meta+Return";
|
||||||
|
command = "ghostty";
|
||||||
|
};
|
||||||
|
|
||||||
|
shortcuts = {
|
||||||
|
kmix = {
|
||||||
|
"decrease_microphone_volume" = "Microphone Volume Down";
|
||||||
|
"decrease_volume" = "Volume Down";
|
||||||
|
"decrease_volume_small" = "Shift+Volume Down";
|
||||||
|
"increase_microphone_volume" = "Microphone Volume Up";
|
||||||
|
"increase_volume" = "Volume Up";
|
||||||
|
"increase_volume_small" = "Shift+Volume Up";
|
||||||
|
"mic_mute" = ["Microphone Mute" "Meta+Volume Mute,Microphone Mute" "Meta+Volume Mute,Mute Microphone"];
|
||||||
|
"mute" = "Volume Mute";
|
||||||
|
};
|
||||||
|
|
||||||
|
mediacontrol = {
|
||||||
|
"mediavolumedown" = "none,,Media volume down";
|
||||||
|
"mediavolumeup" = "none,,Media volume up";
|
||||||
|
"nextmedia" = "Media Next";
|
||||||
|
"pausemedia" = "Media Pause";
|
||||||
|
"playmedia" = "none,,Play media playback";
|
||||||
|
"playpausemedia" = "Media Play";
|
||||||
|
"previousmedia" = "Media Previous";
|
||||||
|
"stopmedia" = "Media Stop";
|
||||||
|
};
|
||||||
|
|
||||||
|
ksmserver = {
|
||||||
|
"Lock Session" = ["Meta+Ctrl+Q" "Screensaver" "Screensaver,Lock Session"];
|
||||||
|
};
|
||||||
|
|
||||||
|
kwin = {
|
||||||
|
"Window Close" = "Meta+Shift+Q";
|
||||||
|
"Kill Window" = "Meta+Ctrl+Esc";
|
||||||
|
"Window Operations Menu" = "Alt+F3";
|
||||||
|
"Window Resize" = "Meta+R,,Resize Window";
|
||||||
|
|
||||||
|
"Overview" = "Meta+Ctrl+W";
|
||||||
|
"Grid View" = "Meta+G";
|
||||||
|
"Edit Tiles" = "Meta+T";
|
||||||
|
|
||||||
|
"Activate Window Demanding Attention" = "Meta+Ctrl+A";
|
||||||
|
|
||||||
|
"Show Desktop" = "Meta+Ctrl+D";
|
||||||
|
|
||||||
|
"Walk Through Windows" = "Alt+Tab";
|
||||||
|
"Walk Through Windows (Reverse)" = "Alt+Shift+Tab";
|
||||||
|
"Walk Through Windows of Current Application" = "Alt+`";
|
||||||
|
"Walk Through Windows of Current Application (Reverse)" = "Alt+~";
|
||||||
|
|
||||||
|
"Window Quick Tile Bottom" = "Meta+Down";
|
||||||
|
"Window Quick Tile Left" = "Meta+Left";
|
||||||
|
"Window Quick Tile Right" = "Meta+Right";
|
||||||
|
"Window Quick Tile Top" = "Meta+Up";
|
||||||
|
|
||||||
|
"Switch to Desktop 1" = "Meta+1";
|
||||||
|
"Switch to Desktop 2" = "Meta+2";
|
||||||
|
"Switch to Desktop 3" = "Meta+3";
|
||||||
|
"Switch to Desktop 4" = "Meta+4";
|
||||||
|
"Switch to Desktop 5" = "Meta+5";
|
||||||
|
"Switch to Desktop 6" = "Meta+6";
|
||||||
|
"Switch to Desktop 7" = "Meta+7";
|
||||||
|
"Switch to Desktop 8" = "Meta+8";
|
||||||
|
"Switch to Desktop 9" = "Meta+9";
|
||||||
|
"Switch to Desktop 10" = "Meta+0";
|
||||||
|
|
||||||
|
"Window to Desktop 1" = "Meta+!"; # Meta+Shift+1
|
||||||
|
"Window to Desktop 2" = "Meta+@"; # Meta+Shift+2
|
||||||
|
"Window to Desktop 3" = "Meta+#"; # Meta+Shift+3
|
||||||
|
"Window to Desktop 4" = "Meta+$"; # Meta+Shift+4
|
||||||
|
"Window to Desktop 5" = "Meta+%"; # Meta+Shift+5
|
||||||
|
"Window to Desktop 6" = "Meta+^"; # Meta+Shift+6
|
||||||
|
"Window to Desktop 7" = "Meta+&"; # Meta+Shift+7
|
||||||
|
"Window to Desktop 8" = "Meta+*"; # Meta+Shift+8
|
||||||
|
"Window to Desktop 9" = "Meta+("; # Meta+Shift+9
|
||||||
|
"Window to Desktop 10" = "Meta+)"; # Meta+Shift+0
|
||||||
|
|
||||||
|
"view_actual_size" = "Meta+Ctrl+=";
|
||||||
|
"view_zoom_in" = ["Meta++" "Meta+=,Meta++" "Meta+=,Zoom In"];
|
||||||
|
"view_zoom_out" = "Meta+-";
|
||||||
|
};
|
||||||
|
"org_kde_powerdevil"."Decrease Keyboard Brightness" = "Keyboard Brightness Down";
|
||||||
|
"org_kde_powerdevil"."Decrease Screen Brightness" = "Monitor Brightness Down";
|
||||||
|
"org_kde_powerdevil"."Decrease Screen Brightness Small" = "Shift+Monitor Brightness Down";
|
||||||
|
"org_kde_powerdevil"."Hibernate" = "Hibernate";
|
||||||
|
"org_kde_powerdevil"."Increase Keyboard Brightness" = "Keyboard Brightness Up";
|
||||||
|
"org_kde_powerdevil"."Increase Screen Brightness" = "Monitor Brightness Up";
|
||||||
|
"org_kde_powerdevil"."Increase Screen Brightness Small" = "Shift+Monitor Brightness Up";
|
||||||
|
"org_kde_powerdevil"."PowerDown" = "Power Down";
|
||||||
|
"org_kde_powerdevil"."PowerOff" = "Power Off";
|
||||||
|
"org_kde_powerdevil"."Sleep" = "Sleep";
|
||||||
|
"org_kde_powerdevil"."Toggle Keyboard Backlight" = "Keyboard Light On/Off";
|
||||||
|
"org_kde_powerdevil"."Turn Off Screen" = [ ];
|
||||||
|
"org_kde_powerdevil"."powerProfile" = ["Battery" "Meta+B,Battery" "Meta+B,Switch Power Profile"];
|
||||||
|
|
||||||
|
plasmashell = {
|
||||||
|
"activate application launcher" = ["Meta" "Alt+F1,Meta" "Alt+F1,Activate Application Launcher"];
|
||||||
|
"activate task manager entry 1" = "none,,";
|
||||||
|
"activate task manager entry 2" = "none,,";
|
||||||
|
"activate task manager entry 3" = "none,,";
|
||||||
|
"activate task manager entry 4" = "none,,";
|
||||||
|
"activate task manager entry 5" = "none,,";
|
||||||
|
"activate task manager entry 6" = "none,,";
|
||||||
|
"activate task manager entry 7" = "none,,";
|
||||||
|
"activate task manager entry 8" = "none,,";
|
||||||
|
"activate task manager entry 9" = "none,,";
|
||||||
|
"activate task manager entry 10" = "none,,";
|
||||||
|
"show activity switcher" = "none,,";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
configFile = {
|
||||||
|
kwinrc.Desktops.Number = {
|
||||||
|
value = 10;
|
||||||
|
immutable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable KWin tiling features
|
||||||
|
kwinrc.Tiling = {
|
||||||
|
# Enable tiling functionality
|
||||||
|
"padding" = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable krohnkite plugin automatically
|
||||||
|
kwinrc.Plugins = {
|
||||||
|
krohnkiteEnabled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
kwinrc.Effect-overview = {
|
||||||
|
# Configure overview effect for better tiling workflow
|
||||||
|
BorderActivate = 9; # Top-left corner activation
|
||||||
|
};
|
||||||
|
|
||||||
|
kcminputrc.Libinput = {
|
||||||
|
AccelerationProfile = "adaptive";
|
||||||
|
PointerAcceleration = 0.5;
|
||||||
|
};
|
||||||
|
|
||||||
|
kcminputrc.Mouse = {
|
||||||
|
X11LibInputXAccelProfileFlat = false;
|
||||||
|
XLbInptAccelProfileFlat = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
kdeglobals.KDE.LookAndFeelPackage = "org.kde.breezedark.desktop";
|
||||||
|
|
||||||
|
# Focus follows mouse configuration
|
||||||
|
kwinrc.Windows = {
|
||||||
|
FocusPolicy = "FocusFollowsMouse";
|
||||||
|
AutoRaise = true; # Set to true if you want windows to auto-raise on focus
|
||||||
|
AutoRaiseInterval = 750; # Delay in ms before auto-raise (if enabled)
|
||||||
|
DelayFocusInterval = 0; # Delay in ms before focus follows mouse
|
||||||
|
};
|
||||||
|
|
||||||
|
# Desktop wallpaper configuration
|
||||||
|
plasma-localerc.Formats.LANG = "en_US.UTF-8";
|
||||||
|
|
||||||
|
# Set wallpaper for all desktops
|
||||||
|
plasmarc.Wallpapers.usersWallpapers = "${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
62
home/roles/tmux/default.nix
Normal file
62
home/roles/tmux/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.tmux;
|
||||||
|
|
||||||
|
tokyo-night = pkgs.tmuxPlugins.mkTmuxPlugin {
|
||||||
|
pluginName = "tokyo-night";
|
||||||
|
rtpFilePath = "tokyo-night.tmux";
|
||||||
|
version = "1.6.1";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "janoamaral";
|
||||||
|
repo = "tokyo-night-tmux";
|
||||||
|
rev = "d610ced20d5f602a7995854931440e4a1e0ab780";
|
||||||
|
sha256 = "sha256-17vEgkL7C51p/l5gpT9dkOy0bY9n8l0/LV51mR1k+V8=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.tmux = {
|
||||||
|
enable = mkEnableOption "tmux terminal multiplexer with Tokyo Night theme";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
programs.tmux.enable = true;
|
||||||
|
programs.tmux.terminal = "tmux-direct";
|
||||||
|
programs.tmux.keyMode = "vi";
|
||||||
|
programs.tmux.escapeTime = 0;
|
||||||
|
programs.tmux.mouse = true;
|
||||||
|
programs.tmux.newSession = true;
|
||||||
|
programs.tmux.historyLimit = 50000;
|
||||||
|
programs.tmux.clock24 = true;
|
||||||
|
programs.tmux.baseIndex = 1;
|
||||||
|
programs.tmux.prefix = "M-\\\\";
|
||||||
|
|
||||||
|
programs.tmux.plugins = with pkgs; [
|
||||||
|
tmuxPlugins.cpu
|
||||||
|
tmuxPlugins.battery
|
||||||
|
tmuxPlugins.better-mouse-mode
|
||||||
|
tmuxPlugins.net-speed
|
||||||
|
tmuxPlugins.online-status
|
||||||
|
tmuxPlugins.pain-control
|
||||||
|
tmuxPlugins.tilish
|
||||||
|
tmuxPlugins.yank
|
||||||
|
|
||||||
|
{
|
||||||
|
plugin = tmuxPlugins.resurrect;
|
||||||
|
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
plugin = tmuxPlugins.continuum;
|
||||||
|
extraConfig = ''
|
||||||
|
set -g @continuum-restore 'on'
|
||||||
|
set -g @continuum-save-interval '15' # minutes
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
||||||
|
tokyo-night
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
home/wallpapers/metroid-samus-returns-kz-3440x1440.jpg
Normal file
BIN
home/wallpapers/metroid-samus-returns-kz-3440x1440.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 MiB |
@@ -24,7 +24,7 @@ with lib;
|
|||||||
};
|
};
|
||||||
kodi = {
|
kodi = {
|
||||||
enable = true;
|
enable = true;
|
||||||
autologin = false;
|
autologin = true;
|
||||||
wayland = true;
|
wayland = true;
|
||||||
};
|
};
|
||||||
users.enable = true;
|
users.enable = true;
|
||||||
@@ -39,12 +39,7 @@ with lib;
|
|||||||
services.xserver.videoDrivers = [ "amdgpu" ];
|
services.xserver.videoDrivers = [ "amdgpu" ];
|
||||||
hardware.graphics.enable = true;
|
hardware.graphics.enable = true;
|
||||||
hardware.graphics.enable32Bit = true;
|
hardware.graphics.enable32Bit = true;
|
||||||
hardware.graphics.extraPackages = with pkgs; [
|
# RADV (AMD's Vulkan driver) is now enabled by default, amdvlk was removed
|
||||||
amdvlk
|
|
||||||
];
|
|
||||||
hardware.graphics.extraPackages32 = with pkgs; [
|
|
||||||
driversi686Linux.amdvlk
|
|
||||||
];
|
|
||||||
|
|
||||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||||
|
|||||||
@@ -65,6 +65,8 @@
|
|||||||
|
|
||||||
# Enable NetworkManager for easy wifi setup
|
# Enable NetworkManager for easy wifi setup
|
||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
|
# Disable wireless networking (conflicts with NetworkManager)
|
||||||
|
networking.wireless.enable = false;
|
||||||
|
|
||||||
# Enable SSH daemon for remote access
|
# Enable SSH daemon for remote access
|
||||||
services.openssh = {
|
services.openssh = {
|
||||||
|
|||||||
@@ -15,12 +15,17 @@
|
|||||||
desktop = {
|
desktop = {
|
||||||
enable = true;
|
enable = true;
|
||||||
wayland = true;
|
wayland = true;
|
||||||
gaming.enable = false;
|
gaming.enable = true;
|
||||||
kde = true;
|
kde = true;
|
||||||
sddm = true;
|
sddm = true;
|
||||||
};
|
};
|
||||||
nfs-mounts.enable = true;
|
nfs-mounts.enable = true;
|
||||||
printing.enable = true;
|
printing.enable = true;
|
||||||
|
remote-build.builders = [{
|
||||||
|
hostName = "zix790prors";
|
||||||
|
maxJobs = 16;
|
||||||
|
speedFactor = 3;
|
||||||
|
}];
|
||||||
spotifyd.enable = true;
|
spotifyd.enable = true;
|
||||||
users = {
|
users = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -37,9 +42,6 @@
|
|||||||
networking.hostName = "nix-book"; # Define your hostname.
|
networking.hostName = "nix-book"; # Define your hostname.
|
||||||
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
||||||
|
|
||||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
|
||||||
|
|
||||||
|
|
||||||
# Enable networking
|
# Enable networking
|
||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
|
|
||||||
|
|||||||
41
machines/nix-deck/configuration.nix
Normal file
41
machines/nix-deck/configuration.nix
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hardware-configuration.nix
|
||||||
|
../../roles/desktop/steamos.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
roles = {
|
||||||
|
audio.enable = true;
|
||||||
|
bluetooth.enable = true;
|
||||||
|
desktop = {
|
||||||
|
enable = true;
|
||||||
|
wayland = true;
|
||||||
|
gaming.enable = true;
|
||||||
|
kde = true;
|
||||||
|
steamos = {
|
||||||
|
enable = true;
|
||||||
|
autoStart = true;
|
||||||
|
desktopSession = "plasma";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
remote-build.builders = [{
|
||||||
|
hostName = "zix790prors";
|
||||||
|
maxJobs = 16;
|
||||||
|
speedFactor = 4; # Prefer remote heavily on Steam Deck
|
||||||
|
}];
|
||||||
|
users = {
|
||||||
|
enable = true;
|
||||||
|
extraGroups = [ "video" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Bootloader
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
networking.hostName = "nix-deck";
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
|
||||||
|
system.stateVersion = "25.05";
|
||||||
|
}
|
||||||
51
machines/nix-deck/hardware-configuration.nix
Normal file
51
machines/nix-deck/hardware-configuration.nix
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Hardware configuration for Steam Deck (nix-deck)
|
||||||
|
# Generated from nixos-generate-config on 2025-11-17
|
||||||
|
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
# Steam Deck specific hardware configuration (Jovian)
|
||||||
|
jovian.devices.steamdeck = {
|
||||||
|
enable = true;
|
||||||
|
autoUpdate = false; # Set to true if you want automatic firmware updates
|
||||||
|
};
|
||||||
|
|
||||||
|
# Kernel modules detected by nixos-generate-config
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"nvme"
|
||||||
|
"xhci_pci"
|
||||||
|
"usb_storage"
|
||||||
|
"uas"
|
||||||
|
"usbhid"
|
||||||
|
"sd_mod"
|
||||||
|
"sdhci_pci"
|
||||||
|
];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-amd" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
# IMPORTANT: Update these filesystem configurations based on your actual partition layout
|
||||||
|
# The configuration below is a placeholder - adjust according to how you partitioned the disk
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-label/nixos";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-label/boot";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [{
|
||||||
|
device = "/swapfile";
|
||||||
|
size = 8192; # 8GB swap file
|
||||||
|
}];
|
||||||
|
|
||||||
|
# AMD CPU microcode updates
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
extraPackages = with pkgs; [
|
extraPackages = with pkgs; [
|
||||||
mesa
|
mesa
|
||||||
libvdpau-va-gl
|
libvdpau-va-gl
|
||||||
vaapiVdpau
|
libva-vdpau-driver
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
|
|||||||
@@ -19,15 +19,16 @@ with lib;
|
|||||||
enable = true;
|
enable = true;
|
||||||
gaming = {
|
gaming = {
|
||||||
enable = true;
|
enable = true;
|
||||||
emulation = true;
|
|
||||||
};
|
};
|
||||||
kde = true;
|
kde = true;
|
||||||
sddm = true;
|
sddm = true;
|
||||||
wayland = true;
|
wayland = true;
|
||||||
|
x11 = true;
|
||||||
};
|
};
|
||||||
nfs-mounts.enable = true;
|
nfs-mounts.enable = true;
|
||||||
nvidia.enable = true;
|
nvidia.enable = true;
|
||||||
printing.enable = true;
|
printing.enable = true;
|
||||||
|
remote-build.enableBuilder = true;
|
||||||
users.enable = true;
|
users.enable = true;
|
||||||
virtualisation.enable = true;
|
virtualisation.enable = true;
|
||||||
};
|
};
|
||||||
@@ -51,19 +52,15 @@ with lib;
|
|||||||
hardware.graphics.enable = true;
|
hardware.graphics.enable = true;
|
||||||
hardware.graphics.enable32Bit = true;
|
hardware.graphics.enable32Bit = true;
|
||||||
|
|
||||||
|
# Set DP-0 as primary display with 164.90Hz refresh rate
|
||||||
|
services.xserver.displayManager.sessionCommands = ''
|
||||||
|
${pkgs.xorg.xrandr}/bin/xrandr --output DP-0 --mode 3440x1440 --rate 164.90 --primary
|
||||||
|
'';
|
||||||
|
|
||||||
hardware.nvidia = {
|
hardware.nvidia = {
|
||||||
# Modesetting is required.
|
|
||||||
modesetting.enable = true;
|
modesetting.enable = true;
|
||||||
|
|
||||||
# Enable the Nvidia settings menu,
|
|
||||||
# accessible via `nvidia-settings`.
|
|
||||||
nvidiaSettings = true;
|
nvidiaSettings = true;
|
||||||
|
|
||||||
# Optionally, you may need to select the appropriate driver version for your specific GPU.
|
|
||||||
package = pkgs.linuxPackages.nvidiaPackages.stable;
|
package = pkgs.linuxPackages.nvidiaPackages.stable;
|
||||||
|
|
||||||
# Use open source kernel modules (recommended for RTX/GTX 16xx and newer)
|
|
||||||
# Set to false if you have an older GPU
|
|
||||||
open = true;
|
open = true;
|
||||||
|
|
||||||
# For gaming performance
|
# For gaming performance
|
||||||
|
|||||||
176
packages/app-launcher-server/app-launcher-server.py
Normal file
176
packages/app-launcher-server/app-launcher-server.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Allowlisted applications that can be launched
|
||||||
|
ALLOWED_APPS = {
|
||||||
|
'firefox': 'firefox',
|
||||||
|
'kodi': 'kodi'
|
||||||
|
}
|
||||||
|
|
||||||
|
def is_app_running(app_name):
|
||||||
|
"""Check if an application is already running, returns (is_running, pid)"""
|
||||||
|
command = ALLOWED_APPS.get(app_name)
|
||||||
|
if not command:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
logger.debug(f"Looking for processes related to app '{app_name}' (command: '{command}')")
|
||||||
|
|
||||||
|
for proc in psutil.process_iter(['name', 'cmdline', 'pid']):
|
||||||
|
try:
|
||||||
|
proc_name = proc.info['name']
|
||||||
|
cmdline = proc.info['cmdline'] or []
|
||||||
|
|
||||||
|
logger.debug(f"Checking process PID {proc.info['pid']}: name='{proc_name}', cmdline={cmdline}")
|
||||||
|
|
||||||
|
# Check multiple patterns for the application:
|
||||||
|
# 1. Process name exactly matches command
|
||||||
|
# 2. Process name contains the command (e.g., "kodi.bin" contains "kodi")
|
||||||
|
# 3. Command line starts with the command
|
||||||
|
# 4. Command line contains the wrapped version (e.g., ".kodi-wrapped")
|
||||||
|
# 5. Any command line argument ends with the command executable
|
||||||
|
|
||||||
|
matches = False
|
||||||
|
match_reason = ""
|
||||||
|
|
||||||
|
if proc_name == command:
|
||||||
|
matches = True
|
||||||
|
match_reason = f"exact process name match: '{proc_name}'"
|
||||||
|
elif command in proc_name:
|
||||||
|
matches = True
|
||||||
|
match_reason = f"process name contains command: '{proc_name}' contains '{command}'"
|
||||||
|
elif cmdline and cmdline[0] == command:
|
||||||
|
matches = True
|
||||||
|
match_reason = f"exact cmdline match: '{cmdline[0]}'"
|
||||||
|
elif cmdline and cmdline[0].endswith('/' + command):
|
||||||
|
matches = True
|
||||||
|
match_reason = f"cmdline path ends with command: '{cmdline[0]}'"
|
||||||
|
elif cmdline and any(f'.{command}-wrapped' in arg for arg in cmdline):
|
||||||
|
matches = True
|
||||||
|
match_reason = f"wrapped command in cmdline: {cmdline}"
|
||||||
|
elif cmdline and any(f'{command}.bin' in arg for arg in cmdline):
|
||||||
|
matches = True
|
||||||
|
match_reason = f"binary command in cmdline: {cmdline}"
|
||||||
|
|
||||||
|
if matches:
|
||||||
|
logger.info(f"Found running {app_name} process: PID {proc.info['pid']} ({match_reason})")
|
||||||
|
return True, proc.info['pid']
|
||||||
|
|
||||||
|
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.debug(f"No running process found for {app_name}")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
class AppLauncherHandler(BaseHTTPRequestHandler):
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
logger.info(format % args)
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == '/':
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
response = {
|
||||||
|
'status': 'running',
|
||||||
|
'available_apps': list(ALLOWED_APPS.keys()),
|
||||||
|
'usage': 'POST /launch/<app_name> to launch an application'
|
||||||
|
}
|
||||||
|
self.wfile.write(json.dumps(response, indent=2).encode())
|
||||||
|
else:
|
||||||
|
self.send_error(404)
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
parsed_path = urlparse(self.path)
|
||||||
|
path_parts = parsed_path.path.strip('/').split('/')
|
||||||
|
|
||||||
|
if len(path_parts) == 2 and path_parts[0] == 'launch':
|
||||||
|
app_name = path_parts[1]
|
||||||
|
self.launch_app(app_name)
|
||||||
|
else:
|
||||||
|
self.send_error(404, "Invalid endpoint. Use /launch/<app_name>")
|
||||||
|
|
||||||
|
def launch_app(self, app_name):
|
||||||
|
if app_name not in ALLOWED_APPS:
|
||||||
|
self.send_error(400, f"Application '{app_name}' not allowed. Available apps: {list(ALLOWED_APPS.keys())}")
|
||||||
|
return
|
||||||
|
|
||||||
|
command = ALLOWED_APPS[app_name]
|
||||||
|
|
||||||
|
# Check if app is already running
|
||||||
|
is_running, existing_pid = is_app_running(app_name)
|
||||||
|
if is_running:
|
||||||
|
logger.info(f"Application {app_name} is already running (PID: {existing_pid}), skipping launch")
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
response = {
|
||||||
|
'status': 'success',
|
||||||
|
'message': f'{app_name} is already running',
|
||||||
|
'pid': existing_pid,
|
||||||
|
'already_running': True
|
||||||
|
}
|
||||||
|
self.wfile.write(json.dumps(response).encode())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Launch the application in the background
|
||||||
|
# Ensure we have the proper environment for GUI apps
|
||||||
|
env = os.environ.copy()
|
||||||
|
|
||||||
|
logger.info(f"Launching application: {command}")
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[command],
|
||||||
|
env=env,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
start_new_session=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
response = {
|
||||||
|
'status': 'success',
|
||||||
|
'message': f'Successfully launched {app_name}',
|
||||||
|
'pid': process.pid,
|
||||||
|
'already_running': False
|
||||||
|
}
|
||||||
|
self.wfile.write(json.dumps(response).encode())
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
logger.error(f"Application not found: {command}")
|
||||||
|
self.send_error(500, f"Application '{app_name}' not found on system")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error launching {command}: {e}")
|
||||||
|
self.send_error(500, f"Failed to launch {app_name}: {str(e)}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8081
|
||||||
|
|
||||||
|
server = HTTPServer(('0.0.0.0', port), AppLauncherHandler)
|
||||||
|
logger.info(f"App launcher server starting on port {port}")
|
||||||
|
logger.info(f"Available applications: {list(ALLOWED_APPS.keys())}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("Server shutting down...")
|
||||||
|
server.server_close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
10
packages/app-launcher-server/default.nix
Normal file
10
packages/app-launcher-server/default.nix
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
let
|
||||||
|
python = pkgs.python3.withPackages (ps: with ps; [
|
||||||
|
psutil
|
||||||
|
]);
|
||||||
|
in
|
||||||
|
pkgs.writeShellScriptBin "app-launcher-server" ''
|
||||||
|
exec ${python}/bin/python3 ${./app-launcher-server.py} "$@"
|
||||||
|
''
|
||||||
116
packages/claude-code/README.md
Normal file
116
packages/claude-code/README.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# claude-cli
|
||||||
|
|
||||||
|
Custom Nix package for Claude Code CLI.
|
||||||
|
|
||||||
|
## Why This Package Exists
|
||||||
|
|
||||||
|
The official `claude-code` package in nixpkgs tries to fetch from npm registry, which is blocked by Block's corporate security (Cloudflare Teams dependency confusion protection). This custom package fetches directly from Anthropic's Google Cloud Storage distribution, bypassing the npm registry entirely.
|
||||||
|
|
||||||
|
## Updating to a New Version
|
||||||
|
|
||||||
|
### Automated Update (Recommended)
|
||||||
|
|
||||||
|
Run the update script to automatically fetch and update to the latest version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd packages/claude-cli
|
||||||
|
./update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will:
|
||||||
|
- Fetch the latest version from Homebrew cask
|
||||||
|
- Update version and all SHA256 hashes in default.nix
|
||||||
|
- Show you what changed
|
||||||
|
|
||||||
|
For a dry-run to see what would change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./update.sh --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
After the script completes, follow the "Test the Build" steps below.
|
||||||
|
|
||||||
|
### Manual Update
|
||||||
|
|
||||||
|
If you prefer to update manually, or if the automated script fails:
|
||||||
|
|
||||||
|
#### 1. Find the Latest Version and Hashes
|
||||||
|
|
||||||
|
Check the Homebrew cask formula for the latest version info:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s "https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/c/claude-code.rb" | head -50
|
||||||
|
```
|
||||||
|
|
||||||
|
This will show:
|
||||||
|
- The latest `version` number
|
||||||
|
- SHA256 hashes for all platforms (`arm64`, `x86_64`, `x86_64_linux`, `arm64_linux`)
|
||||||
|
|
||||||
|
#### 2. Update default.nix
|
||||||
|
|
||||||
|
Edit `default.nix` and update:
|
||||||
|
|
||||||
|
1. The `version` variable (line 9):
|
||||||
|
```nix
|
||||||
|
version = "2.0.51"; # Update this
|
||||||
|
```
|
||||||
|
|
||||||
|
2. All four platform sha256 hashes in the `srcs` attribute set (lines 11-27):
|
||||||
|
```nix
|
||||||
|
aarch64-darwin = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "arm:" value
|
||||||
|
};
|
||||||
|
x86_64-darwin = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "x86_64:" value
|
||||||
|
};
|
||||||
|
x86_64-linux = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "x86_64_linux:" value
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "arm64_linux:" value
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Test the Build
|
||||||
|
|
||||||
|
Before committing, test that the package builds successfully:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NIXPKGS_ALLOW_UNFREE=1 nix-build -E 'with import <nixpkgs> { config.allowUnfree = true; }; callPackage ./packages/claude-cli {}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify the version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./result/bin/claude --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Clean up the test build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm result
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. Deploy
|
||||||
|
|
||||||
|
Commit your changes and rebuild:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add packages/claude-cli/
|
||||||
|
git commit -m "claude-cli: Update to version X.Y.Z"
|
||||||
|
darwin-rebuild switch --flake .#blkfv4yf49kt7
|
||||||
|
```
|
||||||
|
|
||||||
|
## Alternative: Automated Hash Fetching
|
||||||
|
|
||||||
|
If you prefer to fetch hashes automatically, you can use `nix-prefetch-url`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For macOS ARM64 (your current platform)
|
||||||
|
nix-prefetch-url "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/VERSION/darwin-arm64/claude"
|
||||||
|
|
||||||
|
# For other platforms, replace VERSION and adjust the platform string:
|
||||||
|
# darwin-x64, linux-x64, linux-arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
This will download the file and output the SHA256 hash.
|
||||||
60
packages/claude-code/default.nix
Normal file
60
packages/claude-code/default.nix
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, fetchurl
|
||||||
|
, autoPatchelfHook
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
version = "2.0.53";
|
||||||
|
|
||||||
|
srcs = {
|
||||||
|
aarch64-darwin = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-arm64/claude";
|
||||||
|
sha256 = "28c3ad73a20f3ae7ab23efa24d45a9791ccbe071284f1622d4e5e2b89c4a15b7";
|
||||||
|
};
|
||||||
|
x86_64-darwin = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-x64/claude";
|
||||||
|
sha256 = "a27f7b75a51514658640432a0afec8be130673eb7dbecc9a4d742527dd85d29a";
|
||||||
|
};
|
||||||
|
x86_64-linux = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-x64/claude";
|
||||||
|
sha256 = "9c4cc19e207fb6bf7ea140a1580d5ed0dd0a481af471f23614d5a140a4abf1c6";
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-arm64/claude";
|
||||||
|
sha256 = "a5d4044034f3b63c38379bc2dd4067a4dd3c8ec48965ba8e66e3623774a93b72";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
src = srcs.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
|
||||||
|
|
||||||
|
in stdenv.mkDerivation {
|
||||||
|
pname = "claude-code";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
inherit (src) url sha256;
|
||||||
|
};
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = lib.optionals stdenv.isLinux [ autoPatchelfHook ];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
install -Dm755 $src $out/bin/claude
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Terminal-based AI coding assistant from Anthropic";
|
||||||
|
homepage = "https://www.anthropic.com/claude-code";
|
||||||
|
license = licenses.unfree;
|
||||||
|
maintainers = [ ];
|
||||||
|
platforms = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||||
|
mainProgram = "claude";
|
||||||
|
};
|
||||||
|
}
|
||||||
34
packages/claude-code/npm.nix
Normal file
34
packages/claude-code/npm.nix
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{ lib
|
||||||
|
, buildNpmPackage
|
||||||
|
, fetchurl
|
||||||
|
, nodejs_18
|
||||||
|
}:
|
||||||
|
|
||||||
|
buildNpmPackage {
|
||||||
|
pname = "claude-cli";
|
||||||
|
version = "0.2.65";
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.65.tgz";
|
||||||
|
sha256 = "0wwaqq7k9p5aw4vqhfpdgf3da09x64q55wibqaprk6kjvn130i92";
|
||||||
|
};
|
||||||
|
|
||||||
|
npmDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Will be updated after first build
|
||||||
|
|
||||||
|
nodejs = nodejs_18;
|
||||||
|
|
||||||
|
# Don't run npm audit or other network operations during build
|
||||||
|
npmConfigHook = ''
|
||||||
|
npm config set audit false
|
||||||
|
npm config set fund false
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Terminal-based AI coding assistant from Anthropic (npm distribution)";
|
||||||
|
homepage = "https://www.anthropic.com/claude-code";
|
||||||
|
license = licenses.unfree;
|
||||||
|
maintainers = [ ];
|
||||||
|
platforms = platforms.all;
|
||||||
|
mainProgram = "claude";
|
||||||
|
};
|
||||||
|
}
|
||||||
132
packages/claude-code/update.sh
Executable file
132
packages/claude-code/update.sh
Executable file
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DRY_RUN=false
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--dry-run|-n)
|
||||||
|
DRY_RUN=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
echo "Usage: $0 [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --dry-run, -n Show what would be updated without making changes"
|
||||||
|
echo " --help, -h Show this help message"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
echo "Use --help for usage information"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
CASK_URL="https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/c/claude-code.rb"
|
||||||
|
NIX_FILE="$(dirname "$0")/default.nix"
|
||||||
|
|
||||||
|
echo "Fetching latest claude-code version from Homebrew cask..."
|
||||||
|
|
||||||
|
# Fetch the cask file
|
||||||
|
CASK_CONTENT=$(curl -fsSL "$CASK_URL")
|
||||||
|
|
||||||
|
# Extract version (format: version "X.Y.Z")
|
||||||
|
NEW_VERSION=$(echo "$CASK_CONTENT" | grep -m1 'version' | sed -E 's/.*version "([^"]+)".*/\1/')
|
||||||
|
|
||||||
|
# Extract SHA256 hashes (be specific to match sha256 lines only)
|
||||||
|
SHA_ARM=$(echo "$CASK_CONTENT" | grep 'sha256 arm:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
SHA_X86_64=$(echo "$CASK_CONTENT" | grep 'x86_64:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
SHA_X86_64_LINUX=$(echo "$CASK_CONTENT" | grep 'x86_64_linux:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
SHA_ARM64_LINUX=$(echo "$CASK_CONTENT" | grep 'arm64_linux:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
|
||||||
|
# Get current version
|
||||||
|
CURRENT_VERSION=$(grep -m1 'version = ' "$NIX_FILE" | sed -E 's/.*version = "([^"]+)".*/\1/')
|
||||||
|
|
||||||
|
# Validate extracted data
|
||||||
|
if [ -z "$NEW_VERSION" ] || [ -z "$SHA_ARM" ] || [ -z "$SHA_X86_64" ] || [ -z "$SHA_X86_64_LINUX" ] || [ -z "$SHA_ARM64_LINUX" ]; then
|
||||||
|
echo -e "${RED}Error: Failed to extract all required values from Homebrew cask${NC}"
|
||||||
|
echo "Version: $NEW_VERSION"
|
||||||
|
echo "ARM: $SHA_ARM"
|
||||||
|
echo "x86_64: $SHA_X86_64"
|
||||||
|
echo "x86_64_linux: $SHA_X86_64_LINUX"
|
||||||
|
echo "arm64_linux: $SHA_ARM64_LINUX"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if update is needed
|
||||||
|
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
|
||||||
|
echo -e "${GREEN}Already up to date: $CURRENT_VERSION${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Updating from $CURRENT_VERSION to $NEW_VERSION${NC}"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo -e "${YELLOW}DRY RUN - No changes will be made${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Would update:"
|
||||||
|
echo " Version: $CURRENT_VERSION -> $NEW_VERSION"
|
||||||
|
echo " aarch64-darwin SHA: $SHA_ARM"
|
||||||
|
echo " x86_64-darwin SHA: $SHA_X86_64"
|
||||||
|
echo " x86_64-linux SHA: $SHA_X86_64_LINUX"
|
||||||
|
echo " aarch64-linux SHA: $SHA_ARM64_LINUX"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update version
|
||||||
|
sed -i.tmp "s/version = \".*\";/version = \"$NEW_VERSION\";/" "$NIX_FILE"
|
||||||
|
|
||||||
|
# Update SHA256 hashes using awk for more reliable parsing
|
||||||
|
awk -v sha_arm="$SHA_ARM" -v sha_x86="$SHA_X86_64" -v sha_x86_linux="$SHA_X86_64_LINUX" -v sha_arm_linux="$SHA_ARM64_LINUX" '
|
||||||
|
/aarch64-darwin = {/ { in_arm = 1 }
|
||||||
|
/x86_64-darwin = {/ { in_x86 = 1 }
|
||||||
|
/x86_64-linux = {/ { in_x86_linux = 1 }
|
||||||
|
/aarch64-linux = {/ { in_arm_linux = 1 }
|
||||||
|
/};/ {
|
||||||
|
in_arm = 0
|
||||||
|
in_x86 = 0
|
||||||
|
in_x86_linux = 0
|
||||||
|
in_arm_linux = 0
|
||||||
|
}
|
||||||
|
/sha256 = / {
|
||||||
|
if (in_arm) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_arm "\";")
|
||||||
|
} else if (in_x86) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_x86 "\";")
|
||||||
|
} else if (in_x86_linux) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_x86_linux "\";")
|
||||||
|
} else if (in_arm_linux) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_arm_linux "\";")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
' "$NIX_FILE" > "$NIX_FILE.new"
|
||||||
|
|
||||||
|
mv "$NIX_FILE.new" "$NIX_FILE"
|
||||||
|
|
||||||
|
# Clean up temp files
|
||||||
|
rm -f "$NIX_FILE.tmp"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Successfully updated to version $NEW_VERSION${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Updated SHA256 hashes:"
|
||||||
|
echo " aarch64-darwin: $SHA_ARM"
|
||||||
|
echo " x86_64-darwin: $SHA_X86_64"
|
||||||
|
echo " x86_64-linux: $SHA_X86_64_LINUX"
|
||||||
|
echo " aarch64-linux: $SHA_ARM64_LINUX"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Review changes: git diff $NIX_FILE"
|
||||||
|
echo " 2. Test build: NIXPKGS_ALLOW_UNFREE=1 nix-build -E 'with import <nixpkgs> { config.allowUnfree = true; }; callPackage ./packages/claude-code {}'"
|
||||||
|
echo " 3. Verify version: ./result/bin/claude --version"
|
||||||
|
echo " 4. Commit: git add $NIX_FILE && git commit -m 'claude-code: Update to version $NEW_VERSION'"
|
||||||
@@ -2,4 +2,6 @@
|
|||||||
{
|
{
|
||||||
vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {};
|
vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {};
|
||||||
tea-rbw = pkgs.callPackage ./tea-rbw {};
|
tea-rbw = pkgs.callPackage ./tea-rbw {};
|
||||||
|
app-launcher-server = pkgs.callPackage ./app-launcher-server {};
|
||||||
|
claude-code = pkgs.callPackage ./claude-code {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ in
|
|||||||
environment.etc."bashrc".enable = false;
|
environment.etc."bashrc".enable = false;
|
||||||
environment.etc."zshrc".enable = false;
|
environment.etc."zshrc".enable = false;
|
||||||
environment.etc."zshenv".enable = false;
|
environment.etc."zshenv".enable = false;
|
||||||
|
environment.etc."zprofile".enable = false;
|
||||||
|
|
||||||
# Create .local files with nix environment setup
|
# Create .local files with nix environment setup
|
||||||
environment.etc."bash.local".text = ''
|
environment.etc."bash.local".text = ''
|
||||||
@@ -44,6 +45,41 @@ in
|
|||||||
|
|
||||||
time.timeZone = "America/Los_Angeles";
|
time.timeZone = "America/Los_Angeles";
|
||||||
|
|
||||||
|
# System preferences
|
||||||
|
system.defaults = {
|
||||||
|
# Custom keyboard shortcuts
|
||||||
|
CustomUserPreferences = {
|
||||||
|
"com.apple.symbolichotkeys" = {
|
||||||
|
AppleSymbolicHotKeys = {
|
||||||
|
# Screenshot - Capture entire screen (Cmd+Ctrl+3)
|
||||||
|
"28" = {
|
||||||
|
enabled = true;
|
||||||
|
value = {
|
||||||
|
parameters = [ 51 20 1310720 ];
|
||||||
|
type = "standard";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# Screenshot - Capture selected portion (Cmd+Ctrl+4)
|
||||||
|
"30" = {
|
||||||
|
enabled = true;
|
||||||
|
value = {
|
||||||
|
parameters = [ 52 21 1310720 ];
|
||||||
|
type = "standard";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# Screenshot - Show screenshot toolbar (Cmd+Ctrl+5)
|
||||||
|
"184" = {
|
||||||
|
enabled = true;
|
||||||
|
value = {
|
||||||
|
parameters = [ 53 23 1310720 ];
|
||||||
|
type = "standard";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
git
|
git
|
||||||
glances
|
glances
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ with lib;
|
|||||||
./nfs-mounts
|
./nfs-mounts
|
||||||
./nvidia
|
./nvidia
|
||||||
./printing
|
./printing
|
||||||
|
./remote-build
|
||||||
./spotifyd
|
./spotifyd
|
||||||
./users
|
./users
|
||||||
./virtualisation
|
./virtualisation
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ with lib;
|
|||||||
kde = mkOption { type = types.bool; default = false; description = "Enable KDE."; };
|
kde = mkOption { type = types.bool; default = false; description = "Enable KDE."; };
|
||||||
gaming = {
|
gaming = {
|
||||||
enable = mkOption { type = types.bool; default = false; description = "Enable gaming support."; };
|
enable = mkOption { type = types.bool; default = false; description = "Enable gaming support."; };
|
||||||
emulation = mkOption { type = types.bool; default = false; description = "Enable emulation support."; };
|
|
||||||
};
|
};
|
||||||
sddm = mkOption { type = types.bool; default = false; description = "Enable SDDM greeter."; };
|
sddm = mkOption { type = types.bool; default = false; description = "Enable SDDM greeter."; };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,19 +9,27 @@ in
|
|||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
(mkIf (cfg.enable && cfg.gaming.enable) {
|
(mkIf (cfg.enable && cfg.gaming.enable) {
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
steam
|
|
||||||
lutris
|
lutris
|
||||||
moonlight
|
moonlight
|
||||||
];
|
|
||||||
|
|
||||||
# Possibly other gaming specific services or settings
|
# Emulators
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf (cfg.enable && cfg.gaming.emulation) {
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
ryubing
|
|
||||||
dolphin-emu
|
dolphin-emu
|
||||||
|
|
||||||
|
# Re-enabled in 25.11 after binary build was fixed
|
||||||
|
dolphin-emu-primehack
|
||||||
|
|
||||||
|
# Experimenting with just using the steam version + downloading
|
||||||
|
# indiviudal cores
|
||||||
|
#retroarch-full
|
||||||
|
ryubing
|
||||||
];
|
];
|
||||||
|
|
||||||
|
programs.steam = {
|
||||||
|
enable = true;
|
||||||
|
remotePlay.openFirewall = true;
|
||||||
|
dedicatedServer.openFirewall = true;
|
||||||
|
localNetworkGameTransfers.openFirewall = true;
|
||||||
|
};
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,5 +16,22 @@ in
|
|||||||
programs.dconf.enable = true;
|
programs.dconf.enable = true;
|
||||||
services.gnome.gnome-keyring.enable = true;
|
services.gnome.gnome-keyring.enable = true;
|
||||||
programs.kdeconnect.enable = true;
|
programs.kdeconnect.enable = true;
|
||||||
|
|
||||||
|
# XDG Desktop Portal for default application handling in non-KDE environments
|
||||||
|
xdg.portal = {
|
||||||
|
enable = true;
|
||||||
|
extraPortals = with pkgs; [
|
||||||
|
kdePackages.xdg-desktop-portal-kde # For KDE application integration
|
||||||
|
xdg-desktop-portal-gtk # Fallback for GTK applications
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
common = {
|
||||||
|
default = "kde";
|
||||||
|
};
|
||||||
|
i3 = {
|
||||||
|
default = ["kde" "gtk"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
51
roles/desktop/steamos.nix
Normal file
51
roles/desktop/steamos.nix
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{ lib, config, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.roles.desktop;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.roles.desktop.steamos = {
|
||||||
|
enable = mkEnableOption "SteamOS (Jovian) configuration";
|
||||||
|
|
||||||
|
autoStart = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Automatically start Steam Deck UI on boot";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "johno";
|
||||||
|
description = "User to run Steam as";
|
||||||
|
};
|
||||||
|
|
||||||
|
desktopSession = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Desktop session to launch when switching to Desktop Mode";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableDeckyLoader = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable Decky Loader plugin system";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable && cfg.steamos.enable) {
|
||||||
|
jovian.steam = {
|
||||||
|
enable = true;
|
||||||
|
autoStart = cfg.steamos.autoStart;
|
||||||
|
user = cfg.steamos.user;
|
||||||
|
desktopSession = cfg.steamos.desktopSession;
|
||||||
|
};
|
||||||
|
|
||||||
|
jovian.decky-loader.enable = cfg.steamos.enableDeckyLoader;
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
maliit-keyboard
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -12,8 +12,27 @@ in
|
|||||||
|
|
||||||
windowManager.i3 = {
|
windowManager.i3 = {
|
||||||
enable = true;
|
enable = true;
|
||||||
extraPackages = with pkgs; [ dmenu i3status i3lock ];
|
extraPackages = with pkgs; [
|
||||||
|
dmenu
|
||||||
|
i3status
|
||||||
|
i3lock
|
||||||
|
polkit_gnome # GNOME polkit authentication agent (more stable with i3)
|
||||||
|
picom # Compositor for smooth rendering (important for Nvidia)
|
||||||
|
networkmanagerapplet # NetworkManager system tray applet
|
||||||
|
ddcutil # DDC/CI monitor control for brightness
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Enable DDC/CI support for monitor brightness control
|
||||||
|
boot.kernelModules = [ "i2c-dev" ];
|
||||||
|
|
||||||
|
# Add ddcutil udev rules and user permissions
|
||||||
|
hardware.i2c.enable = true;
|
||||||
|
|
||||||
|
# Install ddcutil system-wide
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
ddcutil
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ in
|
|||||||
wayland = mkOption {
|
wayland = mkOption {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
appLauncherServer = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable HTTP app launcher server for remote control";
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 8081;
|
||||||
|
description = "Port for the app launcher HTTP server";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -33,24 +45,39 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
allowedTCPPorts = [ 8080 ];
|
allowedTCPPorts = [ 8080 ] ++ optional cfg.appLauncherServer.enable cfg.appLauncherServer.port;
|
||||||
allowedUDPPorts = [ 8080 ];
|
allowedUDPPorts = [ 8080 ];
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
kodiPkg
|
kodiPkg
|
||||||
wget
|
wget
|
||||||
];
|
firefox
|
||||||
|
] ++ optional cfg.appLauncherServer.enable pkgs.custom.app-launcher-server;
|
||||||
|
|
||||||
programs.kdeconnect.enable = true;
|
programs.kdeconnect.enable = true;
|
||||||
|
|
||||||
services = if cfg.autologin then {
|
systemd.user.services = mkIf cfg.appLauncherServer.enable {
|
||||||
displayManager = {
|
app-launcher-server = {
|
||||||
autoLogin.enable = true;
|
description = "HTTP App Launcher Server";
|
||||||
autoLogin.user = "kodi";
|
wantedBy = [ "graphical-session.target" ];
|
||||||
defaultSession = "kodi";
|
after = [ "graphical-session.target" ];
|
||||||
sessionData.autologinSession = "plasma";
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${pkgs.custom.app-launcher-server}/bin/app-launcher-server ${toString cfg.appLauncherServer.port}";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5s";
|
||||||
|
Environment = [
|
||||||
|
"PATH=${pkgs.firefox}/bin:${kodiPkg}/bin:/run/current-system/sw/bin"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
} else {};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.displayManager = mkIf cfg.autologin {
|
||||||
|
autoLogin.enable = true;
|
||||||
|
autoLogin.user = "kodi";
|
||||||
|
defaultSession = "plasma";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,5 +26,11 @@ in
|
|||||||
model = "everywhere";
|
model = "everywhere";
|
||||||
}];
|
}];
|
||||||
hardware.printers.ensureDefaultPrinter = "MFC-L8900CDW_series";
|
hardware.printers.ensureDefaultPrinter = "MFC-L8900CDW_series";
|
||||||
|
|
||||||
|
# Fix ensure-printers service to wait for network availability
|
||||||
|
systemd.services.ensure-printers = {
|
||||||
|
after = [ "cups.service" "network-online.target" ];
|
||||||
|
wants = [ "cups.service" "network-online.target" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
132
roles/remote-build/default.nix
Normal file
132
roles/remote-build/default.nix
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
{ lib, config, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.roles.remote-build;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.roles.remote-build = {
|
||||||
|
enableBuilder = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Enable this machine as a remote build host for other machines";
|
||||||
|
};
|
||||||
|
|
||||||
|
builderUser = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "nix-builder";
|
||||||
|
description = "User account for remote builders to connect as";
|
||||||
|
};
|
||||||
|
|
||||||
|
builders = mkOption {
|
||||||
|
type = types.listOf (types.submodule {
|
||||||
|
options = {
|
||||||
|
hostName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Hostname or IP address of the build machine";
|
||||||
|
};
|
||||||
|
|
||||||
|
systems = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ "x86_64-linux" ];
|
||||||
|
description = "Supported systems";
|
||||||
|
};
|
||||||
|
|
||||||
|
maxJobs = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 8;
|
||||||
|
description = "Maximum number of parallel build jobs";
|
||||||
|
};
|
||||||
|
|
||||||
|
speedFactor = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 2;
|
||||||
|
description = "Speed factor compared to local building (higher = prefer remote)";
|
||||||
|
};
|
||||||
|
|
||||||
|
supportedFeatures = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
|
||||||
|
description = "Supported build features";
|
||||||
|
};
|
||||||
|
|
||||||
|
sshUser = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "nix-builder";
|
||||||
|
description = "SSH user for connecting to the builder";
|
||||||
|
};
|
||||||
|
|
||||||
|
sshKey = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = "Path to SSH private key for authentication";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
default = [];
|
||||||
|
description = "List of remote build machines to use";
|
||||||
|
};
|
||||||
|
|
||||||
|
fallbackToLocalBuild = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Fallback to local building if remote builders are unavailable";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
# Builder host configuration
|
||||||
|
(mkIf cfg.enableBuilder {
|
||||||
|
# Create dedicated builder user
|
||||||
|
users.users.${cfg.builderUser} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = cfg.builderUser;
|
||||||
|
description = "Nix remote build user";
|
||||||
|
home = "/var/lib/${cfg.builderUser}";
|
||||||
|
createHome = true;
|
||||||
|
shell = pkgs.bashInteractive;
|
||||||
|
openssh.authorizedKeys.keyFiles = []; # Will be populated by client machines
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.${cfg.builderUser} = {};
|
||||||
|
|
||||||
|
# Ensure home directory has correct permissions
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/lib/${cfg.builderUser} 0700 ${cfg.builderUser} ${cfg.builderUser} -"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Allow builder user to perform builds
|
||||||
|
nix.settings.trusted-users = [ cfg.builderUser ];
|
||||||
|
|
||||||
|
# Allow remote builds
|
||||||
|
services.openssh.enable = true;
|
||||||
|
|
||||||
|
# Ensure nix-daemon is accessible
|
||||||
|
nix.settings.allowed-users = [ "*" ];
|
||||||
|
})
|
||||||
|
|
||||||
|
# Client configuration (machines using remote builders)
|
||||||
|
(mkIf (cfg.builders != []) {
|
||||||
|
nix.buildMachines = map (builder: {
|
||||||
|
hostName = builder.hostName;
|
||||||
|
systems = builder.systems;
|
||||||
|
maxJobs = builder.maxJobs;
|
||||||
|
speedFactor = builder.speedFactor;
|
||||||
|
supportedFeatures = builder.supportedFeatures;
|
||||||
|
sshUser = builder.sshUser;
|
||||||
|
sshKey = builder.sshKey;
|
||||||
|
}) cfg.builders;
|
||||||
|
|
||||||
|
nix.distributedBuilds = true;
|
||||||
|
|
||||||
|
# Use substitutes from remote builders
|
||||||
|
nix.extraOptions = ''
|
||||||
|
builders-use-substitutes = true
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Fallback to local build if remote unavailable
|
||||||
|
nix.settings.fallback = cfg.fallbackToLocalBuild;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user