From 106198878c82360240d1fcdb7de9afc542f38d32 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 16 Dec 2025 07:14:29 -0300 Subject: [PATCH 1/3] virtualisation usb passthrough --- hosts/modules/libvirtd.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hosts/modules/libvirtd.nix b/hosts/modules/libvirtd.nix index aa2ae71..6bd154f 100644 --- a/hosts/modules/libvirtd.nix +++ b/hosts/modules/libvirtd.nix @@ -1,7 +1,10 @@ { ... }: { - virtualisation.libvirtd.enable = true; + virtualisation = { + libvirtd.enable = true; + spiceUSBRedirection.enable = true; + }; programs.virt-manager.enable = true; From 97b0b01a48f0de1197bd9cdd88800dd12c0aeb65 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 16 Dec 2025 08:09:57 -0300 Subject: [PATCH 2/3] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nix-ai-tools': 'github:numtide/nix-ai-tools/053759f30ef14cbd87c0a1a1d3e7c729ca0db83f?narHash=sha256-VPcX5z0A58pcbRb3I42fBig3zTPm9a71iwrfgkte2J4%3D' (2025-12-14) → 'github:numtide/llm-agents.nix/9ee377d02d7e50e2903d9c7fa53138aebd9ae944?narHash=sha256-yrECdmBoMhUAA8FqUJ1LbtDjuwn%2B38OkFgRrwbEq/DU%3D' (2025-12-16) • Updated input 'nix-ai-tools/nixpkgs': 'github:NixOS/nixpkgs/23735a82a828372c4ef92c660864e82fbe2f5fbe?narHash=sha256-yqHBL2wYGwjGL2GUF2w3tofWl8qO9tZEuI4wSqbCrtE%3D' (2025-12-13) → 'github:NixOS/nixpkgs/09b8fda8959d761445f12b55f380d90375a1d6bb?narHash=sha256-aq%2BdQoaPONOSjtFIBnAXseDm9TUhIbe215TPmkfMYww%3D' (2025-12-15) --- flake.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flake.lock b/flake.lock index 6920bc0..fe378cf 100644 --- a/flake.lock +++ b/flake.lock @@ -513,16 +513,16 @@ "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1765719830, - "narHash": "sha256-VPcX5z0A58pcbRb3I42fBig3zTPm9a71iwrfgkte2J4=", + "lastModified": 1765854155, + "narHash": "sha256-yrECdmBoMhUAA8FqUJ1LbtDjuwn+38OkFgRrwbEq/DU=", "owner": "numtide", - "repo": "nix-ai-tools", - "rev": "053759f30ef14cbd87c0a1a1d3e7c729ca0db83f", + "repo": "llm-agents.nix", + "rev": "9ee377d02d7e50e2903d9c7fa53138aebd9ae944", "type": "github" }, "original": { "owner": "numtide", - "repo": "nix-ai-tools", + "repo": "llm-agents.nix", "type": "github" } }, @@ -764,11 +764,11 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1765644376, - "narHash": "sha256-yqHBL2wYGwjGL2GUF2w3tofWl8qO9tZEuI4wSqbCrtE=", + "lastModified": 1765772535, + "narHash": "sha256-aq+dQoaPONOSjtFIBnAXseDm9TUhIbe215TPmkfMYww=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "23735a82a828372c4ef92c660864e82fbe2f5fbe", + "rev": "09b8fda8959d761445f12b55f380d90375a1d6bb", "type": "github" }, "original": { From c9ab6d881e57025f38a496ec29a155a90bef244f Mon Sep 17 00:00:00 2001 From: William Date: Tue, 16 Dec 2025 10:18:38 -0300 Subject: [PATCH 3/3] claude-desktop package --- flake.nix | 2 +- overlays.nix | 1 + packages.nix | 1 + packages/claude-desktop.nix | 221 ++++++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 packages/claude-desktop.nix diff --git a/flake.nix b/flake.nix index d65e9d8..20210f2 100644 --- a/flake.nix +++ b/flake.nix @@ -50,7 +50,7 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - nix-ai-tools.url = "github:numtide/nix-ai-tools"; + nix-ai-tools.url = "github:numtide/llm-agents.nix"; vicinae.url = "github:vicinaehq/vicinae"; }; diff --git a/overlays.nix b/overlays.nix index eab4edf..b8f807f 100644 --- a/overlays.nix +++ b/overlays.nix @@ -4,6 +4,7 @@ flake.overlays = { default = final: prev: { base16-schemes = inputs.self.packages.${final.system}.base16-schemes; + claude-desktop = inputs.self.packages.${final.system}.claude-desktop; fastfetch = inputs.self.packages.${final.system}.fastfetch; hm-cli = inputs.self.packages.${final.system}.hm-cli; kwrite = inputs.self.packages.${final.system}.kwrite; diff --git a/packages.nix b/packages.nix index 46979f8..e6f571d 100644 --- a/packages.nix +++ b/packages.nix @@ -6,6 +6,7 @@ { packages = { base16-schemes = pkgs.callPackage ./packages/base16-schemes.nix { }; + claude-desktop = pkgs.callPackage ./packages/claude-desktop.nix { }; fastfetch = pkgs.callPackage ./packages/fastfetch.nix { }; hm-cli = pkgs.callPackage ./packages/hm-cli.nix { }; kwrite = pkgs.callPackage ./packages/kwrite.nix { }; diff --git a/packages/claude-desktop.nix b/packages/claude-desktop.nix new file mode 100644 index 0000000..e72fc37 --- /dev/null +++ b/packages/claude-desktop.nix @@ -0,0 +1,221 @@ +{ + lib, + stdenv, + fetchurl, + makeWrapper, + makeDesktopItem, + copyDesktopItems, + p7zip, + unzip, + electron, + nodejs, + asar, + graphicsmagick, +}: + +let + pname = "claude-desktop"; + version = "1.0.1768"; # Updated based on extracted nupkg + + srcs.x86_64-linux = fetchurl { + url = "https://downloads.claude.ai/releases/win32/x64/1.0.1768/Claude-67d01376d0e9d08b328455f6db9e63b0d603506a.exe"; + hash = "sha256-x76Qav38ya3ObpWIq3dDowo79LgvVquMfaZeH8M1LUk=;"; + }; + + src = + srcs.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); + + # Stub implementation for claude-native module + claudeNativeStub = '' + // Stub implementation of claude-native using KeyboardKey enum values + const KeyboardKey = { + Backspace: 43, Tab: 280, Enter: 261, Shift: 272, Control: 61, Alt: 40, + CapsLock: 56, Escape: 85, Space: 276, PageUp: 251, PageDown: 250, + End: 83, Home: 154, LeftArrow: 175, UpArrow: 282, RightArrow: 262, + DownArrow: 81, Delete: 79, Meta: 187 + }; + Object.freeze(KeyboardKey); + module.exports = { + getWindowsVersion: () => "10.0.0", + setWindowEffect: () => {}, + removeWindowEffect: () => {}, + getIsMaximized: () => false, + flashFrame: () => {}, + clearFlashFrame: () => {}, + showNotification: () => {}, + setProgressBar: () => {}, + clearProgressBar: () => {}, + setOverlayIcon: () => {}, + clearOverlayIcon: () => {}, + KeyboardKey + }; + ''; + +in +stdenv.mkDerivation rec { + inherit pname version src; + + nativeBuildInputs = [ + makeWrapper + copyDesktopItems + p7zip + unzip + nodejs + graphicsmagick + ]; + + buildInputs = [ + electron + ]; + + desktopItems = [ + (makeDesktopItem { + name = "claude-desktop"; + desktopName = "Claude"; + comment = "AI assistant from Anthropic"; + exec = "claude-desktop %u"; + icon = "claude-desktop"; + categories = [ + "Network" + "Chat" + "Office" + ]; + mimeTypes = [ "x-scheme-handler/claude" ]; + startupNotify = true; + startupWMClass = "Claude"; + }) + ]; + + unpackPhase = '' + runHook preUnpack + + # Extract the Windows installer - use -y to auto-overwrite + 7z x -y $src -o./extracted + + # The installer contains a NuGet package + if [ -f ./extracted/AnthropicClaude-*-full.nupkg ]; then + echo "Found NuGet package, extracting..." + # NuGet packages are just zip files + unzip -q ./extracted/AnthropicClaude-*-full.nupkg -d ./nupkg + + # Extract app.asar to modify it + if [ -f ./nupkg/lib/net45/resources/app.asar ]; then + echo "Extracting app.asar..." + ${asar}/bin/asar extract ./nupkg/lib/net45/resources/app.asar ./app + + # Also copy the unpacked resources + if [ -d ./nupkg/lib/net45/resources/app.asar.unpacked ]; then + cp -r ./nupkg/lib/net45/resources/app.asar.unpacked/* ./app/ + fi + + # Copy additional resources + mkdir -p ./app/resources + mkdir -p ./app/resources/i18n + cp ./nupkg/lib/net45/resources/Tray* ./app/resources/ || true + cp ./nupkg/lib/net45/resources/*-*.json ./app/resources/i18n/ || true + fi + else + echo "NuGet package not found" + ls -la ./extracted/ + exit 1 + fi + + runHook postUnpack + ''; + + buildPhase = '' + runHook preBuild + + # Replace the Windows-specific claude-native module with a stub + if [ -d ./app/node_modules/claude-native ]; then + echo "Replacing claude-native module with Linux stub..." + rm -rf ./app/node_modules/claude-native/*.node + cat > ./app/node_modules/claude-native/index.js << 'EOF' + ${claudeNativeStub} + EOF + fi + + # Fix the title bar detection (from aaddrick script) + echo "Fixing title bar detection..." + SEARCH_BASE="./app/.vite/renderer/main_window/assets" + if [ -d "$SEARCH_BASE" ]; then + TARGET_FILE=$(find "$SEARCH_BASE" -type f -name "MainWindowPage-*.js" | head -1) + if [ -n "$TARGET_FILE" ]; then + echo "Found target file: $TARGET_FILE" + # Replace patterns like 'if(!VAR1 && VAR2)' with 'if(VAR1 && VAR2)' + sed -i -E 's/if\(!([a-zA-Z]+)[[:space:]]*&&[[:space:]]*([a-zA-Z]+)\)/if(\1 \&\& \2)/g' "$TARGET_FILE" + echo "Title bar fix applied" + fi + fi + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/lib/claude-desktop + + # Repack the modified app as app.asar + cd ./app + ${asar}/bin/asar pack . ../app.asar + cd .. + + # Copy resources + mkdir -p $out/lib/claude-desktop/resources + cp ./app.asar $out/lib/claude-desktop/resources/ + + # Create app.asar.unpacked directory with the stub + mkdir -p $out/lib/claude-desktop/resources/app.asar.unpacked/node_modules/claude-native + cat > $out/lib/claude-desktop/resources/app.asar.unpacked/node_modules/claude-native/index.js << 'EOF' + ${claudeNativeStub} + EOF + + # Copy other resources + if [ -d ./nupkg/lib/net45/resources ]; then + cp ./nupkg/lib/net45/resources/*.png $out/lib/claude-desktop/resources/ 2>/dev/null || true + cp ./nupkg/lib/net45/resources/*.ico $out/lib/claude-desktop/resources/ 2>/dev/null || true + cp ./nupkg/lib/net45/resources/*.json $out/lib/claude-desktop/resources/ 2>/dev/null || true + fi + + # Create wrapper script + makeWrapper ${electron}/bin/electron $out/bin/claude-desktop \ + --add-flags "$out/lib/claude-desktop/resources/app.asar" \ + --set DISABLE_AUTOUPDATER 1 \ + --set NODE_ENV production + + # Extract and install icons in multiple sizes + if [ -f ./extracted/setupIcon.ico ]; then + echo "Converting and installing icons..." + # Count frames in the ICO file and extract each one + frame_count=$(gm identify ./extracted/setupIcon.ico | wc -l) + for i in $(seq 0 $((frame_count - 1))); do + gm convert "./extracted/setupIcon.ico[$i]" "./extracted/setupIcon-$i.png" 2>/dev/null || true + done + + # Loop through converted icons and install them by size + for img in ./extracted/setupIcon-*.png; do + if [ -f "$img" ]; then + size=$(gm identify -format "%wx%h" "$img") + # Skip smallest icons (16x16 and 32x32) as they're too low quality + if [ "$size" != "16x16" ] && [ "$size" != "32x32" ]; then + mkdir -p "$out/share/icons/hicolor/$size/apps" + cp "$img" "$out/share/icons/hicolor/$size/apps/claude-desktop.png" + fi + fi + done + fi + + runHook postInstall + ''; + + meta = with lib; { + description = "Claude Desktop - AI assistant from Anthropic"; + homepage = "https://claude.ai"; + license = licenses.unfree; + sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ]; + maintainers = with maintainers; [ ]; + platforms = [ "x86_64-linux" ]; + mainProgram = "claude-desktop"; + }; +}