From d3790a167bb9b6676d49e10083efb43968f6fb9d Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Sun, 12 Apr 2026 22:38:09 +0900 Subject: [PATCH] chore: update --- .gitignore | 52 +++++++++++ .gitmodules | 0 default-configurations/gitignore | 18 ++++ flake.lock | 139 +++++++++++++++++++++++------ flake.nix | 60 +++++++++---- home/.config/fish/config.fish | 3 + home/.config/nushell/config.nu | 14 +++ home/.config/nushell/env.nu | 3 + nix/claude-vm/default.nix | 29 ++++++ nix/claude-vm/installer.nix | 64 +++++++++++++ nix/docker-images/nix-node.nix | 113 ----------------------- nix/hardware/claude-vm.nix | 41 +++++++++ nix/hardware/mini.nix | 31 ++++--- nix/hardware/nvidia.nix | 2 + nix/personal/default.nix | 13 ++- nix/personal/graphical/default.nix | 76 +++++++++------- nix/personal/graphical/steam.nix | 4 +- nix/personal/graphical/vscode.nix | 17 ++-- nix/personal/home.nix | 61 +++++++++++-- nix/personal/tui.nix | 3 + nix/qemu.nix | 21 +++++ nix/server/nginx.nix | 10 +++ nix/server/secrets.nix | 2 +- nix/server/secrets.yaml | 10 ++- nix/server/xray.nix | 4 +- nix/xray.nix | 70 +++++++++++++++ scripts/run-claude-vm.sh | 84 +++++++++++++++++ 27 files changed, 715 insertions(+), 229 deletions(-) create mode 100644 .gitmodules create mode 100644 home/.config/nushell/config.nu create mode 100644 home/.config/nushell/env.nu create mode 100644 nix/claude-vm/default.nix create mode 100644 nix/claude-vm/installer.nix delete mode 100644 nix/docker-images/nix-node.nix create mode 100644 nix/hardware/claude-vm.nix create mode 100644 nix/qemu.nix create mode 100644 nix/xray.nix create mode 100755 scripts/run-claude-vm.sh diff --git a/.gitignore b/.gitignore index d132e40..28b8e3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,55 @@ /result +/result-fd /.env /claude-docker +/.claude-vm + +# editors +.vscode/ +.idea/ +.godot/ + +# apple +.DS_Store +.AppleDouble +.LSOverride + +# build related directories +/build +target +result +zig-out +zig-build + +# secrets +.env + +# direnv +.envrc +.direnv + +# py +__pycache__/ +.pytest_cache +.mypy_cache +.ruff_cache +.coverage* +core.[0-9]* + +# claude sandbox +/.bash_profile +/.bashrc +/.gitconfig +/.mcp.json +/.profile +/.ripgreprc +/.zprofile +/.zshrc +/HEAD +/config +/hooks +/objects +/refs +.claude/agents +.claude/commands +.claude/settings.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/default-configurations/gitignore b/default-configurations/gitignore index 959ff33..c9ff129 100644 --- a/default-configurations/gitignore +++ b/default-configurations/gitignore @@ -29,3 +29,21 @@ __pycache__/ .ruff_cache .coverage* core.[0-9]* + +# claude sandbox +/.bash_profile +/.bashrc +/.gitconfig +/.mcp.json +/.profile +/.ripgreprc +/.zprofile +/.zshrc +/HEAD +/config +/hooks +/objects +/refs +.claude/agents +.claude/commands +.claude/settings.json diff --git a/flake.lock b/flake.lock index ca114c7..80f6b77 100644 --- a/flake.lock +++ b/flake.lock @@ -1,13 +1,52 @@ { "nodes": { + "claude-code": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1775007163, + "narHash": "sha256-plS86OtgkWsAf/NtXc5iwxpBB+cOuyqjo5Xq2gEg8FQ=", + "owner": "sadjow", + "repo": "claude-code-nix", + "rev": "335c96551a1650e0306b756039f15c3364d2e0ac", + "type": "github" + }, + "original": { + "owner": "sadjow", + "repo": "claude-code-nix", + "type": "github" + } + }, + "code-flake": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1774250740, + "narHash": "sha256-xQogXLfvKA/gw3BfxwbS89sVHnoiLbCHrvwTFnOgWk8=", + "owner": "kp2pml30", + "repo": "code-flake", + "rev": "982adef5d1e5bdb4e1095aad5a635cef5d6c8510", + "type": "github" + }, + "original": { + "owner": "kp2pml30", + "repo": "code-flake", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { - "lastModified": 1733328505, - "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "owner": "edolstra", "repo": "flake-compat", - "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { @@ -17,6 +56,24 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { "inputs": { "systems": [ "kp2pml30-moe", @@ -44,41 +101,40 @@ ] }, "locked": { - "lastModified": 1758463745, - "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", + "lastModified": 1773963144, + "narHash": "sha256-WzBOBfSay3GYilUfKaUa1Mbf8/jtuAiJIedx7fWuIX4=", "owner": "nix-community", "repo": "home-manager", - "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", + "rev": "a91b3ea73a765614d90360580b689c48102d1d33", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-25.05", + "ref": "release-25.11", "repo": "home-manager", "type": "github" } }, "kp2pml30-moe": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "nixpkgs": [ "nixpkgs" ], "rust-overlay": "rust-overlay", - "systems": "systems" + "systems": "systems_2" }, "locked": { - "lastModified": 1770820613, - "narHash": "sha256-I5lMXVML0491AqfSI8DUnw3mhIwCLIfQWwZwrdeRrZY=", + "lastModified": 1775030101, + "narHash": "sha256-huBQI29iONwcRYDQDZlce60OjbRgsd7AN1f8EGYyf+Y=", "owner": "kp2pml30", "repo": "kp2pml30.github.io", - "rev": "73cbd5858e7196c236029f86756119806d484612", + "rev": "1deafcacbaa870308dee0467f08fa8a77a733861", "type": "github" }, "original": { "owner": "kp2pml30", "repo": "kp2pml30.github.io", - "rev": "73cbd5858e7196c236029f86756119806d484612", "type": "github" } }, @@ -105,11 +161,11 @@ ] }, "locked": { - "lastModified": 1742568034, - "narHash": "sha256-QaMEhcnscfF2MqB7flZr+sLJMMYZPnvqO4NYf9B4G38=", + "lastModified": 1769813415, + "narHash": "sha256-nnVmNNKBi1YiBNPhKclNYDORoHkuKipoz7EtVnXO50A=", "owner": "nix-community", "repo": "nixos-generators", - "rev": "42ee229088490e3777ed7d1162cb9e9d8c3dbb11", + "rev": "8946737ff703382fda7623b9fab071d037e897d5", "type": "github" }, "original": { @@ -126,11 +182,11 @@ ] }, "locked": { - "lastModified": 1744290088, - "narHash": "sha256-/X9XVEl0EiyisNbF5srrxXRSVoRqdwExuqyspYqqEjQ=", + "lastModified": 1773882647, + "narHash": "sha256-VzcOcE0LLpEnyoxLuMuptZ9ZWCkSBn99bTgEQoz5Viw=", "owner": "nix-community", "repo": "NixOS-WSL", - "rev": "60b4904a1390ac4c89e93d95f6ed928975e525ed", + "rev": "fd0eae98d1ecee31024271f8d64676250a386ee7", "type": "github" }, "original": { @@ -141,6 +197,22 @@ } }, "nixpkgs": { + "locked": { + "lastModified": 1774855581, + "narHash": "sha256-YkreHeMgTCYvJ5fESV0YyqQK49bHGe2B51tH6claUh4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "15c6719d8c604779cf59e03c245ea61d3d7ab69b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1736320768, "narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=", @@ -156,13 +228,13 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs_3": { "locked": { - "lastModified": 1770056022, - "narHash": "sha256-yvCz+Qmci1bVucXEyac3TdoSPMtjqVJmVy5wro6j/70=", + "lastModified": 1773964973, + "narHash": "sha256-NV/J+tTER0P5iJhUDL/8HO5MDjDceLQPRUYgdmy5wXw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d04d8548aed39902419f14a8537006426dc1e4fa", + "rev": "812b3986fd1568f7a858f97fcf425ad996ba7d25", "type": "github" }, "original": { @@ -174,16 +246,18 @@ }, "root": { "inputs": { + "claude-code": "claude-code", + "code-flake": "code-flake", "home-manager": "home-manager", "kp2pml30-moe": "kp2pml30-moe", "nixos-generators": "nixos-generators", "nixos-wsl": "nixos-wsl", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_3" } }, "rust-overlay": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1743682350, @@ -214,6 +288,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 09ea0b3..fd785bb 100644 --- a/flake.nix +++ b/flake.nix @@ -6,37 +6,33 @@ inputs.nixpkgs.follows = "nixpkgs"; }; home-manager = { - url = "github:nix-community/home-manager/release-25.05"; + url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; nixos-generators = { url = "github:nix-community/nixos-generators"; inputs.nixpkgs.follows = "nixpkgs"; }; - #vscode-server = { - # url = "github:nix-community/nixos-vscode-server"; - # inputs.nixpkgs.follows = "nixpkgs"; - #}; - kp2pml30-moe = { - url = "github:kp2pml30/kp2pml30.github.io/73cbd5858e7196c236029f86756119806d484612"; + url = "github:kp2pml30/kp2pml30.github.io"; inputs.nixpkgs.follows = "nixpkgs"; }; + + code-flake = { + url = "github:kp2pml30/code-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + claude-code.url = "github:sadjow/claude-code-nix"; }; - outputs = inputs@{ self, nixpkgs, nixos-wsl, home-manager, nixos-generators, kp2pml30-moe, ... }: + outputs = inputs@{ self, nixpkgs, nixos-wsl, home-manager, nixos-generators, kp2pml30-moe, code-flake, claude-code, ... }: let rootPath = self; additionalArgs = { inherit inputs rootPath; }; lib = nixpkgs.lib; in { - packages.x86_64-linux.docker-nix-node = import ./nix/docker-images/nix-node.nix { - pkgs = import nixpkgs { system = "x86_64-linux"; }; - inherit lib; - rootPath = self; - }; - nixosConfigurations = { server = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; @@ -75,9 +71,8 @@ networking.hostId = "e31a5cc2"; time.timeZone = "Asia/Tokyo"; - environment.systemPackages = [ - # pkgs.claude-code - ]; + + nixpkgs.overlays = [ claude-code.overlays.default code-flake.overlays.default ]; }) ./nix/hardware/mini.nix @@ -86,6 +81,10 @@ ./nix/personal + ./nix/qemu.nix + + ./nix/xray.nix + { kp2pml30 = { xserver = true; @@ -94,6 +93,11 @@ opera = true; steam = true; + qemu = true; + + xray-client = true; + xray-client-id = "mini"; + boot.efiGrub = true; hardware.wireless = true; @@ -114,6 +118,8 @@ networking.hostId = "e31a5cc0"; time.timeZone = "Asia/Yerevan"; + + nixpkgs.overlays = [ code-flake.overlays.default ]; } ./nix/hardware/ideapad.nix @@ -154,6 +160,26 @@ ]; specialArgs = additionalArgs; }; + + claude-vm = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + { networking.hostId = "c1a0de00"; } + ./nix/common.nix + ./nix/claude-vm + ./nix/personal + ./nix/hardware/claude-vm.nix + ]; + specialArgs = additionalArgs; + }; + + claude-vm-installer = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./nix/claude-vm/installer.nix + ]; + specialArgs = additionalArgs; + }; }; }; } diff --git a/home/.config/fish/config.fish b/home/.config/fish/config.fish index 36f8662..7eea1bf 100644 --- a/home/.config/fish/config.fish +++ b/home/.config/fish/config.fish @@ -7,6 +7,9 @@ if status is-interactive if command -v zoxide > /dev/null zoxide init fish | source end + if command -v carapace > /dev/null + carapace _carapace | source + end end export GPG_TTY=(tty) diff --git a/home/.config/nushell/config.nu b/home/.config/nushell/config.nu new file mode 100644 index 0000000..90b3035 --- /dev/null +++ b/home/.config/nushell/config.nu @@ -0,0 +1,14 @@ +source $"($nu.cache-dir)/carapace.nu" + +let carapace_completer = {|spans| + carapace $spans.0 nushell ...$spans | from json +} + +$env.config.completions = { + algorithm: "fuzzy" + external: { + enable: true + max_results: 100 + completer: $carapace_completer + } +} diff --git a/home/.config/nushell/env.nu b/home/.config/nushell/env.nu new file mode 100644 index 0000000..b58a271 --- /dev/null +++ b/home/.config/nushell/env.nu @@ -0,0 +1,3 @@ +$env.CARAPACE_BRIDGES = 'zsh,fish,bash,inshellisense' +mkdir $"($nu.cache-dir)" +carapace _carapace nushell | save --force $"($nu.cache-dir)/carapace.nu" diff --git a/nix/claude-vm/default.nix b/nix/claude-vm/default.nix new file mode 100644 index 0000000..ee613e7 --- /dev/null +++ b/nix/claude-vm/default.nix @@ -0,0 +1,29 @@ +{ pkgs, lib, ... }: +{ + users.mutableUsers = false; + + users.users.claude = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + shell = pkgs.fish; + hashedPassword = ""; + }; + + users.users.root.hashedPassword = ""; + + security.sudo.wheelNeedsPassword = false; + + programs.fish.enable = true; + + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "yes"; + PermitEmptyPasswords = "yes"; + }; + }; + + networking.firewall.allowedTCPPorts = [ 22 ]; + + nix.settings.trusted-users = [ "root" "claude" ]; +} diff --git a/nix/claude-vm/installer.nix b/nix/claude-vm/installer.nix new file mode 100644 index 0000000..83f79ef --- /dev/null +++ b/nix/claude-vm/installer.nix @@ -0,0 +1,64 @@ +{ pkgs, lib, rootPath, modulesPath, ... }: +let + install-claude-vm = pkgs.writeShellScriptBin "install-claude-vm" '' + set -euo pipefail + + DISK="/dev/vda" + + echo "=== claude-vm installer ===" + echo "Target disk: $DISK" + + # Partition: MBR with single root partition + echo "Partitioning..." + parted -s "$DISK" -- \ + mklabel msdos \ + mkpart primary ext4 1MiB 100% + + # Format with label + echo "Formatting..." + mkfs.ext4 -L nixos "''${DISK}1" + + # Mount + echo "Mounting..." + mount "''${DISK}1" /mnt + + # Copy flake source + echo "Copying flake to /mnt/dotfiles..." + mkdir -p /mnt/dotfiles + cp -a /etc/dotfiles-src/. /mnt/dotfiles/ + + # Install + echo "Running nixos-install..." + nixos-install --flake /mnt/dotfiles#claude-vm --no-root-passwd --show-trace + + echo "=== Installation complete! Shutting down... ===" + ${pkgs.systemd}/bin/systemctl poweroff + ''; +in +{ + imports = [ + "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" + ]; + + # Serial console for -nographic QEMU + boot.kernelParams = [ "console=ttyS0,115200n8" ]; + boot.loader.timeout = lib.mkForce 5; + + environment.etc."dotfiles-src".source = rootPath; + + environment.systemPackages = [ install-claude-vm ]; + + # Auto-run installer on boot + systemd.services.auto-install = { + description = "Automatic claude-vm installation"; + after = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + path = with pkgs; [ nix nixos-install-tools util-linux coreutils git curl wget binutils e2fsprogs dosfstools parted ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${install-claude-vm}/bin/install-claude-vm"; + StandardOutput = "journal+console"; + StandardError = "journal+console"; + }; + }; +} diff --git a/nix/docker-images/nix-node.nix b/nix/docker-images/nix-node.nix deleted file mode 100644 index 18e3537..0000000 --- a/nix/docker-images/nix-node.nix +++ /dev/null @@ -1,113 +0,0 @@ -{ pkgs, lib, rootPath }: -let - user = "devuser"; - uid = "1000"; - gid = "1000"; - - baseVim = rootPath + "/home/.config/nvim/base.vim"; - - fromGitHub = rev: repo: pkgs.vimUtils.buildVimPlugin { - pname = "${lib.strings.sanitizeDerivationName repo}"; - version = rev; - src = builtins.fetchGit { - url = "https://github.com/${repo}.git"; - inherit rev; - }; - }; - - customNeovim = pkgs.neovim.override { - configure = { - customRC = builtins.readFile baseVim; - packages.myPlugins = with pkgs.vimPlugins; { - start = [ - nvim-treesitter.withAllGrammars - nvim-autopairs - nerdtree - tokyonight-nvim - barbar-nvim - ((fromGitHub "3587f57480b88e8009df7b36dc84e9c7ff8f2c49" "famiu/feline.nvim").overrideAttrs (old: { - doCheck = false; - })) - (fromGitHub "d63c811337b2f75de52f16efee176695f31e7fbc" "timakro/vim-yadi") - (fromGitHub "aafa5c187a15701a7299a392b907ec15d9a7075f" "nvim-tree/nvim-web-devicons") - ]; - }; - }; - }; - - # Create passwd/group/shadow as a package - userSetup = pkgs.runCommand "user-setup" {} '' - mkdir -p $out/etc - echo "root:x:0:0:root:/root:/bin/bash" > $out/etc/passwd - echo "${user}:x:${uid}:${gid}:${user}:/home/${user}:${pkgs.bash}/bin/bash" >> $out/etc/passwd - - echo "root:x:0:" > $out/etc/group - echo "${user}:x:${gid}:" >> $out/etc/group - - echo "root:!:1::::::" > $out/etc/shadow - echo "${user}:!:1::::::" >> $out/etc/shadow - - mkdir -p $out/etc/nix - cat > $out/etc/nix/nix.conf < $out/etc/sudoers.d/${user} - chmod 440 $out/etc/sudoers.d/${user} - - mkdir -p $out/tmp - chmod 1777 $out/tmp - ''; - - entrypoint = pkgs.writeShellScriptBin "entrypoint" '' - if ! command -v claude &> /dev/null; then - echo "Installing claude-code..." - npm install -g @anthropic-ai/claude-code - fi - exec "$@" - ''; -in -pkgs.dockerTools.buildLayeredImage { - name = "nix-node"; - tag = "latest"; - contents = with pkgs; [ - nix - nodejs - bash - coreutils - cacert - git - fish - curl - wget - htop - sudo - customNeovim - userSetup - entrypoint - ]; - fakeRootCommands = '' - mkdir -p ./home/${user}/.npm-global - chown -R ${uid}:${gid} ./home/${user} - - mkdir -p ./usr/bin - ln -s ${pkgs.coreutils}/bin/env ./usr/bin/env - ''; - enableFakechroot = true; - config = { - Entrypoint = [ "${entrypoint}/bin/entrypoint" ]; - Cmd = [ "${pkgs.bash}/bin/bash" ]; - User = "${user}"; - WorkingDir = "/home/${user}"; - Env = [ - "HOME=/home/${user}" - "USER=${user}" - "NIX_PAGER=cat" - "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" - "NIX_CONF_DIR=/etc/nix" - "NPM_CONFIG_PREFIX=/home/${user}/.npm-global" - "PATH=/home/${user}/.npm-global/bin:/usr/bin:/bin" - ]; - }; -} diff --git a/nix/hardware/claude-vm.nix b/nix/hardware/claude-vm.nix new file mode 100644 index 0000000..070f726 --- /dev/null +++ b/nix/hardware/claude-vm.nix @@ -0,0 +1,41 @@ +{ lib, ... }: +{ + imports = [ + ./common.nix + ]; + + boot.initrd.availableKernelModules = [ + "virtio_pci" + "virtio_blk" + "virtio_net" + "virtio_balloon" + "virtio_scsi" + "xhci_pci" + "ahci" + "usbhid" + ]; + + boot.kernelParams = [ "console=ttyS0,115200n8" ]; + boot.loader.efi.canTouchEfiVariables = lib.mkForce false; + boot.loader.grub = { + enable = true; + device = "/dev/vda"; + extraConfig = '' + serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1 + terminal_input serial console + terminal_output serial console + ''; + }; + + fileSystems."/" = { + device = "/dev/disk/by-label/nixos"; + fsType = "ext4"; + }; + + services.qemuGuest.enable = true; + + networking = { + hostName = "claude-vm"; + useDHCP = true; + }; +} diff --git a/nix/hardware/mini.nix b/nix/hardware/mini.nix index d2c3bde..0f2d048 100644 --- a/nix/hardware/mini.nix +++ b/nix/hardware/mini.nix @@ -21,15 +21,24 @@ options = [ "fmask=0077" "dmask=0077" ]; }; -# fileSystems."/mnt/d" = { -# device = "/dev/sda1"; -# fsType = "exfat"; -# options = [ -# "users" -# "exec" -# "nofail" -# ]; -# }; + fileSystems."/mnt/d" = { + device = "/dev/sda1"; + fsType = "exfat"; + options = [ + "users" + "exec" + "nofail" + ]; + }; + + fileSystems."/mnt/d/SteamLibrary/steamapps/compatdata" = { + device = "/home/kp2pml30/.local/share/Steam/steamapps/compatdata-d"; + fsType = "none"; + options = [ + "bind" + "nofail" + ]; + }; swapDevices = [ { device = "/dev/disk/by-uuid/c68daa9f-f165-4e23-8710-2aab0ad8d282"; } ]; @@ -44,8 +53,8 @@ programs.nix-ld.enable = true; - home-manager.users.${config.kp2pml30.username}.programs.git.extraConfig = { - user.signingkey = "0xCD6528BAC23E3E34!"; + home-manager.users.${config.kp2pml30.username}.programs.git.settings = { + user.signingkey = "0x1739F9D8BA250D04!"; commit.gpgsign = true; tag.gpgSign = true; }; diff --git a/nix/hardware/nvidia.nix b/nix/hardware/nvidia.nix index 7c9227e..db91825 100644 --- a/nix/hardware/nvidia.nix +++ b/nix/hardware/nvidia.nix @@ -13,4 +13,6 @@ open = true; nvidiaSettings = true; }; + + hardware.nvidia-container-toolkit.enable = true; } diff --git a/nix/personal/default.nix b/nix/personal/default.nix index 3e3cf37..1ed8e1f 100644 --- a/nix/personal/default.nix +++ b/nix/personal/default.nix @@ -6,6 +6,8 @@ }@args: let cfg = config.kp2pml30; + startsWith = prefix: str: + builtins.substring 0 (builtins.stringLength prefix) str == prefix; in { options.kp2pml30 = { username = lib.mkOption { @@ -65,22 +67,17 @@ in { fish fishPlugins.grc fishPlugins.bass + nushell + carapace python312 # needed for bass grc ]; nixpkgs.config.allowUnfreePredicate = pkg: + builtins.any (x: startsWith x (pkgs.lib.getName pkg)) [ "vscode" "steam" "nvidia" ] || builtins.elem (pkgs.lib.getName pkg) [ "anytype-heart" - "vscode" - "steam" - "steam-run" - "steam-original" - "steam-unwrapped" - "nvidia-x11" - "nvidia-settings" - "nvidia-persistenced" "opera" "discord" "slack" diff --git a/nix/personal/graphical/default.nix b/nix/personal/graphical/default.nix index 679a617..9a1d907 100644 --- a/nix/personal/graphical/default.nix +++ b/nix/personal/graphical/default.nix @@ -17,37 +17,49 @@ in { ./messengers-work.nix ]; - xdg.portal = { - enable = true; - extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + config = { + assertions = [ + { assertion = cfg.kitty -> cfg.xserver; message = "kp2pml30.kitty requires kp2pml30.xserver"; } + { assertion = cfg.vscode -> cfg.xserver; message = "kp2pml30.vscode requires kp2pml30.xserver"; } + { assertion = cfg.opera -> cfg.xserver; message = "kp2pml30.opera requires kp2pml30.xserver"; } + { assertion = cfg.steam -> cfg.xserver; message = "kp2pml30.steam requires kp2pml30.xserver"; } + { assertion = cfg.messengers.personal -> cfg.xserver; message = "kp2pml30.messengers.personal requires kp2pml30.xserver"; } + { assertion = cfg.messengers.work -> cfg.xserver; message = "kp2pml30.messengers.work requires kp2pml30.xserver"; } + ]; + } // lib.mkIf cfg.xserver { + xdg.portal = { + enable = true; + extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + config.common.default = "*"; + }; + services.flatpak.enable = true; + systemd.services.flatpak-repo = { + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.flatpak ]; + script = '' + flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + ''; + }; + + environment.systemPackages = with pkgs; [ + #anytype + flatpak + gnome-software + firefox + feh + vlc + ]; + + fonts.enableDefaultPackages = true; + fonts.packages = with pkgs; [ + noto-fonts + noto-fonts-cjk-sans + noto-fonts-cjk-sans + + fira-code + fira-code-symbols + + nerd-fonts.fira-code + ]; }; - services.flatpak.enable = true; - systemd.services.flatpak-repo = { - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.flatpak ]; - script = '' - flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo - ''; - }; - - environment.systemPackages = with pkgs; [ - anytype - flatpak - gnome-software - - nodePackages.npm - nodejs - ]; - - fonts.enableDefaultPackages = true; - fonts.packages = with pkgs; [ - noto-fonts - noto-fonts-cjk-sans - noto-fonts-cjk-sans - - fira-code - fira-code-symbols - - nerd-fonts.fira-code - ]; } diff --git a/nix/personal/graphical/steam.nix b/nix/personal/graphical/steam.nix index 5e8cfe6..e5b0748 100644 --- a/nix/personal/graphical/steam.nix +++ b/nix/personal/graphical/steam.nix @@ -9,9 +9,9 @@ let in lib.mkIf cfg.steam { programs.steam = { enable = true; - remotePlay.openFirewall = false; + remotePlay.openFirewall = true; dedicatedServer.openFirewall = false; - localNetworkGameTransfers.openFirewall = false; + localNetworkGameTransfers.openFirewall = true; }; hardware.steam-hardware.enable = true; diff --git a/nix/personal/graphical/vscode.nix b/nix/personal/graphical/vscode.nix index 5f28a48..0767d4b 100644 --- a/nix/personal/graphical/vscode.nix +++ b/nix/personal/graphical/vscode.nix @@ -10,15 +10,16 @@ in lib.mkIf cfg.vscode { home-manager.users.${cfg.username} = { programs.vscode = { enable = true; - package = (pkgs.vscode.overrideAttrs (oldAttrs: rec { - src = (builtins.fetchTarball { - url = "https://update.code.visualstudio.com/1.104.1/linux-x64/stable"; - sha256 = "sha256:109mdk1v323dyhzrq0444gjjhfpjxbllkqkhsapfj44ypjzdjcy8"; - }); - version = "1.102.2"; - })); + package = pkgs.vscode.overrideAttrs (oldAttrs: { + buildInputs = (oldAttrs.buildInputs or []) ++ [ + pkgs.curl + pkgs.openssl + pkgs.webkitgtk_4_1 + pkgs.libsoup_3 + ]; + }); mutableExtensionsDir = false; - userSettings = lib.importJSON("${rootPath}/vscode/settings.json"); + profiles.default.userSettings = lib.importJSON("${rootPath}/vscode/settings.json"); # extensions = with pkgs; [ # vscode-extensions.eamodio.gitlens # vscode-extensions.editorconfig.editorconfig diff --git a/nix/personal/home.nix b/nix/personal/home.nix index 2151584..eab03bc 100644 --- a/nix/personal/home.nix +++ b/nix/personal/home.nix @@ -18,7 +18,7 @@ in { home-manager.users.${cfg.username} = { lib, ... }: { home = { - stateVersion = "24.05"; + stateVersion = "25.11"; username = cfg.username; homeDirectory = "/home/${cfg.username}"; packages = with pkgs; [ @@ -41,16 +41,16 @@ in { nix.gc = { automatic = true; - frequency = "weekly"; + dates = "weekly"; }; programs = { git = { enable = true; - userName = cfg.username; - userEmail = "kp2pml30@gmail.com"; lfs.enable = true; - extraConfig = { + settings = { + user.name = cfg.username; + user.email = "kp2pml30@gmail.com"; init.defaultBranch = "main"; }; }; @@ -60,6 +60,12 @@ in { shellInitLast = builtins.readFile (rootPath + "/home/.config/fish/config.fish"); }; + nushell = { + enable = true; + extraEnv = builtins.readFile (rootPath + "/home/.config/nushell/env.nu"); + extraConfig = builtins.readFile (rootPath + "/home/.config/nushell/config.nu"); + }; + starship = { enable = true; settings = { @@ -80,7 +86,50 @@ in { }; }; - dconf.settings = { + xdg.desktopEntries = lib.mkIf config.kp2pml30.xserver { + yazi = { + name = "Yazi"; + comment = "Terminal file manager"; + exec = "kitty -- yazi %u"; + terminal = false; + mimeType = [ "inode/directory" ]; + categories = [ "System" "FileManager" ]; + }; + nvim = { + name = "Neovim"; + comment = "Terminal text editor"; + exec = "kitty -- nvim %F"; + terminal = false; + mimeType = [ "text/plain" ]; + categories = [ "Utility" "TextEditor" ]; + }; + }; + + xdg.mimeApps = lib.mkIf config.kp2pml30.xserver (let + mimeMap = desktop: types: + builtins.listToAttrs (map (t: { name = t; value = [ desktop ]; }) types); + in { + enable = true; + defaultApplications = + { "inode/directory" = [ "yazi.desktop" ]; } + // mimeMap "nvim.desktop" [ + "text/plain" "text/html" "text/css" "text/xml" "text/markdown" + "text/x-csrc" "text/x-chdr" "text/x-c++src" "text/x-c++hdr" + "text/x-python" "text/x-shellscript" "text/x-makefile" + "application/json" "application/xml" "application/x-yaml" + "application/toml" "application/javascript" "application/x-shellscript" + "application/x-nix" + ] + // mimeMap "feh.desktop" [ + "image/png" "image/jpeg" "image/gif" "image/webp" "image/bmp" "image/svg+xml" + ] + // mimeMap "vlc.desktop" [ + "video/mp4" "video/x-matroska" "video/webm" "video/x-msvideo" + "video/quicktime" "video/x-flv" + ]; + }); + + dconf.settings = lib.mkIf config.kp2pml30.xserver { "org/gnome/desktop/interface" = { color-scheme = "prefer-dark"; }; diff --git a/nix/personal/tui.nix b/nix/personal/tui.nix index 693d721..a92348c 100644 --- a/nix/personal/tui.nix +++ b/nix/personal/tui.nix @@ -8,6 +8,7 @@ let cfg = config.kp2pml30; in { config = { + nixpkgs.overlays = [ inputs.claude-code.overlays.default ]; programs = { tmux.enable = true; yazi.enable = true; @@ -18,6 +19,8 @@ in { ncdu timewarrior p7zip + claude-code + lazydocker ]; }; diff --git a/nix/qemu.nix b/nix/qemu.nix new file mode 100644 index 0000000..c0e2721 --- /dev/null +++ b/nix/qemu.nix @@ -0,0 +1,21 @@ +{ config +, pkgs +, lib +, ... +}: +let + cfg = config.kp2pml30; +in { + options.kp2pml30.qemu = lib.mkEnableOption ""; + + config = lib.mkIf cfg.qemu { + environment.systemPackages = with pkgs; [ + qemu + OVMF + ]; + + virtualisation.libvirtd.enable = true; + + users.users.${cfg.username}.extraGroups = [ "libvirtd" ]; + }; +} diff --git a/nix/server/nginx.nix b/nix/server/nginx.nix index cc3ab34..aa0ee42 100644 --- a/nix/server/nginx.nix +++ b/nix/server/nginx.nix @@ -124,6 +124,16 @@ in lib.mkIf cfg.nginx { root = cfg.sitePath; tryFiles = "$uri $uri/ /index.html"; }; + + locations."/fs/" = { + root = cfg.sitePath; + tryFiles = "$uri $uri/ /fs/index.html"; + }; + + locations."/view/" = { + root = cfg.sitePath; + tryFiles = "$uri $uri/ /view/index.html"; + }; }; } // (if cfg.xray then { # Xray fallback proxy servers diff --git a/nix/server/secrets.nix b/nix/server/secrets.nix index b075827..1d10edc 100644 --- a/nix/server/secrets.nix +++ b/nix/server/secrets.nix @@ -23,7 +23,7 @@ let fi # Decrypt and parse XRAY_UIDS - ${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./secrets.yaml}" | ${pkgs.yq}/bin/yq '.XRAY_UIDS[]' -r + ${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./secrets.yaml}" | ${pkgs.yq}/bin/yq '.XRAY_UIDS[].uid' -r ''; xray-config-base = builtins.toFile "xray.json" (builtins.toJSON ( diff --git a/nix/server/secrets.yaml b/nix/server/secrets.yaml index de129d6..c17e5e8 100644 --- a/nix/server/secrets.yaml +++ b/nix/server/secrets.yaml @@ -1,4 +1,6 @@ -U2FsdGVkX18N4BW9sin9kPVNkpbtVNoDqBAm+080vcYSS7qySHVOCfe94a7S8mh4 -G5tbvoRrOFxJ+RW/WYNMsEZ7wgsJM8b9AiKPaT30BMHXriTdtai80i6xKqv9zdCb -moGUlBSgMtqEhvAnvpYBxHQ+NtDhxw7K9UjaO7eodNp+l9PR6z+IeL29rC2DMxQc -jXAjbfPa3aeSikXF0g118HbUwVJQwlXq99n/fjkJ8XOhBo/S4tWbt0U8O97VKlA6 +U2FsdGVkX18Z/nFLuSfx9e8XYdUPqLO0NOAdKcPf+WkKg7exhD+p6p+pDzaHhdHP +0JzWp5p8yz/sehmSoqrXJtS7G9Y5f9gj2dLwfxLobzx4TTR/s8Hz2qVyNKu+D8hP +vBkNQaMJQNjPgJHsmKDnqT0zFGr0nz5GfchMbxepherBdysuwZKk7j7X0TKcgA0R +c4v+QWYZH669dWij2Oq9P6IFE/aM420cmSXh2Ilr/MMirk/rZ3dr3Kx0JdVHaeFT +VAHU243eV0++OpvL9td7r8L9BWBS2p/5nowN5mVcUmBBBF7FrYeDaYjkoi3IXLTb +1EfrTOpIQfgm7qOqsfy1lClfrHaKPadqyIYxkuY+i/k= diff --git a/nix/server/xray.nix b/nix/server/xray.nix index 49fcf35..318f051 100644 --- a/nix/server/xray.nix +++ b/nix/server/xray.nix @@ -13,9 +13,9 @@ in lib.mkIf cfg.xray { }; # Ensure xray can read the certificates - users.users.xray.extraGroups = [ "nginx" ]; + users.users.xray.extraGroups = [ "certreaders" ]; # Ensure the xray service starts after ACME certificates are available systemd.services.xray.after = [ "acme-${cfg.hostname}.service" ]; systemd.services.xray.wants = [ "acme-${cfg.hostname}.service" ]; -} \ No newline at end of file +} diff --git a/nix/xray.nix b/nix/xray.nix new file mode 100644 index 0000000..09f1837 --- /dev/null +++ b/nix/xray.nix @@ -0,0 +1,70 @@ +{ config +, pkgs +, lib +, ... +}: +let + cfg = config.kp2pml30; + + xray-config-base = builtins.toFile "xray-client.json" (builtins.toJSON + (builtins.fromJSON (builtins.readFile ./server/xray-client.json)) + ); + + decryptSecrets = pkgs.writeShellScript "decrypt-secrets" '' + set -euo pipefail + + source /var/lib/secrets/.env + + if [ -z "''${KP2_DOTFILES_SECRET_KEY:-}" ]; then + echo "Error: KP2_DOTFILES_SECRET_KEY environment variable not set" >&2 + exit 1 + fi + + ${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./server/secrets.yaml}" | ${pkgs.yq}/bin/yq --arg id "${cfg.xray-client-id}" '.XRAY_UIDS[] | select(.id == $id) | .uid' -r + ''; + + generateXrayConfig = pkgs.writeShellScript "generate-xray-client-config" '' + set -euo pipefail + + UUID=$(${decryptSecrets}) + + cat "${xray-config-base}" | \ + ${pkgs.jq}/bin/jq --arg uuid "$UUID" '.outbounds[0].settings.vnext[0].users[0].id = $uuid' + ''; +in { + options.kp2pml30.xray-client = lib.mkEnableOption ""; + options.kp2pml30.xray-client-id = lib.mkOption { + type = lib.types.str; + description = "ID to select the correct UUID from secrets"; + }; + + config = lib.mkIf cfg.xray-client { + services.xray = { + enable = true; + settingsFile = "/run/secrets/xray-client-config.json"; + }; + + systemd.services.xray-client-secrets = { + description = "Generate Xray client configuration"; + wantedBy = [ "xray.service" ]; + before = [ "xray.service" ]; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + EnvironmentFile = "/var/lib/secrets/.env"; + }; + + script = '' + mkdir -p /run/secrets + ${generateXrayConfig} > /run/secrets/xray-client-config.json + chmod 444 /run/secrets/xray-client-config.json + ''; + }; + + systemd.tmpfiles.rules = [ + "d /var/lib/secrets 0750 root root -" + "d /run/secrets 0755 root root -" + ]; + }; +} diff --git a/scripts/run-claude-vm.sh b/scripts/run-claude-vm.sh new file mode 100755 index 0000000..620554f --- /dev/null +++ b/scripts/run-claude-vm.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -exuo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FLAKE_DIR="$(dirname "$SCRIPT_DIR")" +VM_DIR="$FLAKE_DIR/.claude-vm" +DISK="$VM_DIR/disk.qcow2" +DISK_SIZE="20G" +RAM="12G" +CPUS="8" +SSH_PORT="2222" + +mkdir -p "$VM_DIR" + +qemu_base_args=( + -machine q35 + -cpu host + -enable-kvm + -m "$RAM" + -smp "$CPUS" + -drive "file=$DISK,format=qcow2,if=virtio" + -device virtio-net-pci,netdev=net0 + -netdev "user,id=net0,hostfwd=tcp::${SSH_PORT}-:22" + -nographic + -fsdev local,id=fsdev0,path=$VM_DIR/share,security_model=passthrough -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=hostshare +) + +do_install() { + echo "=== Building installer ISO... ===" + ISO_PATH=$(nix build "${FLAKE_DIR}#nixosConfigurations.claude-vm-installer.config.system.build.isoImage" --no-link --print-out-paths) + ISO_FILE=$(find "$ISO_PATH/iso" -name '*.iso' | head -1) + + if [ -z "$ISO_FILE" ]; then + echo "Error: ISO not found after build" + exit 1 + fi + + echo "ISO: $ISO_FILE" + + # Create fresh disk + rm -f "$DISK" + qemu-img create -f qcow2 "$DISK" "$DISK_SIZE" + + echo "=== Booting installer (fully automatic)... ===" + qemu-system-x86_64 \ + "${qemu_base_args[@]}" \ + -cdrom "$ISO_FILE" \ + -boot d + + echo "=== Installation finished. Run without --install to boot the VM. ===" +} + +do_run() { + if [ ! -f "$DISK" ]; then + echo "No disk image found. Run with --install first." + exit 1 + fi + + echo "=== Booting claude-vm (SSH: localhost:${SSH_PORT}) ===" + qemu-system-x86_64 \ + "${qemu_base_args[@]}" +} + +case "${1:-}" in + --install) + do_install + ;; + --run) + do_run + ;; + "") + if [ ! -f "$DISK" ]; then + do_install + fi + do_run + ;; + *) + echo "Usage: $0 [--install|--run]" + echo " --install Build ISO and install to disk" + echo " --run Boot installed disk" + echo " (none) Install if needed, then run" + exit 1 + ;; +esac