diff --git a/packages/claude-code/package-lock.json b/packages/claude-code/package-lock.json deleted file mode 100644 index 96083b9..0000000 --- a/packages/claude-code/package-lock.json +++ /dev/null @@ -1,334 +0,0 @@ -{ - "name": "@anthropic-ai/claude-code", - "version": "2.1.112", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@anthropic-ai/claude-code", - "version": "2.1.112", - "license": "SEE LICENSE IN README.md", - "bin": { - "claude": "cli.js" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "^0.34.2", - "@img/sharp-darwin-x64": "^0.34.2", - "@img/sharp-linux-arm": "^0.34.2", - "@img/sharp-linux-arm64": "^0.34.2", - "@img/sharp-linux-x64": "^0.34.2", - "@img/sharp-linuxmusl-arm64": "^0.34.2", - "@img/sharp-linuxmusl-x64": "^0.34.2", - "@img/sharp-win32-arm64": "^0.34.2", - "@img/sharp-win32-x64": "^0.34.2" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - } - } -} diff --git a/packages/claude-code/package.nix b/packages/claude-code/package.nix index 5c36c07..76e29ef 100644 --- a/packages/claude-code/package.nix +++ b/packages/claude-code/package.nix @@ -1,41 +1,75 @@ { pkgs, ... }: -pkgs.buildNpmPackage (finalAttrs: { - pname = "claude-code"; - version = "2.1.112"; +let + inherit (pkgs) stdenv lib; + version = "2.1.114"; - src = pkgs.fetchzip { - url = "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-${finalAttrs.version}.tgz"; - hash = "sha256-SJJqU7XHbu9IRGPMJNUg6oaMZiQUKqJhI2wm7BnR1gs="; + # upstream ships platform-native binaries as separate npm packages under + # @anthropic-ai/claude-code-; the wrapper package is just a + # postinstall shim that copies the matching one into place + sources = { + "x86_64-linux" = { + slug = "linux-x64"; + hash = "sha256-gejcdjRzKnWsvLzxJLfdjr+PeYdOR9tkCOL8owuJuf8="; + }; + "aarch64-linux" = { + slug = "linux-arm64"; + hash = "sha256-atThX6FuIJe0t7pQRd76ZIVCPd+AKfkLl1a48eLglQE="; + }; + "x86_64-darwin" = { + slug = "darwin-x64"; + hash = "sha256-1tUHaaE4AI8r7W+vS4wCKTH3OjDOxMRtSzyUt+LHhAs="; + }; + "aarch64-darwin" = { + slug = "darwin-arm64"; + hash = "sha256-Nx0I2PZgoLeI43c5O4rlyPgEQGDom3RO5pemV9V1vqg="; + }; }; - npmDepsHash = "sha256-bdkej9Z41GLew9wi1zdNX+Asauki3nT1+SHmBmaUIBU="; + source = + sources.${stdenv.hostPlatform.system} + or (throw "claude-code: unsupported system ${stdenv.hostPlatform.system}"); +in +stdenv.mkDerivation { + pname = "claude-code"; + inherit version; - strictDeps = true; + src = pkgs.fetchzip { + url = "https://registry.npmjs.org/@anthropic-ai/claude-code-${source.slug}/-/claude-code-${source.slug}-${version}.tgz"; + inherit (source) hash; + }; - postPatch = '' - cp ${./package-lock.json} package-lock.json + nativeBuildInputs = [ + pkgs.makeWrapper + ] ++ lib.optionals stdenv.hostPlatform.isLinux [ pkgs.patchelf ]; - substituteInPlace cli.js \ - --replace-fail '#!/bin/sh' '#!/usr/bin/env sh' + dontBuild = true; + dontConfigure = true; + dontStrip = true; + + installPhase = '' + runHook preInstall + install -Dm755 claude $out/bin/claude + runHook postInstall ''; - dontNpmBuild = true; - - env.AUTHORIZED = "1"; - - postInstall = '' + # NOTE:(@janezicmatej) upstream is a bun single-file-executable; the + # embedded script payload sits at the tail of the ELF, so autoPatchelfHook's + # section-layout changes corrupt it — only the interpreter can be rewritten + postFixup = lib.optionalString stdenv.hostPlatform.isLinux '' + patchelf --set-interpreter ${stdenv.cc.bintools.dynamicLinker} $out/bin/claude + '' + '' wrapProgram $out/bin/claude \ --set DISABLE_AUTOUPDATER 1 \ --set-default FORCE_AUTOUPDATE_PLUGINS 1 \ --set DISABLE_INSTALLATION_CHECKS 1 \ --unset DEV \ --prefix PATH : ${ - pkgs.lib.makeBinPath ( + lib.makeBinPath ( [ pkgs.procps ] - ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ + ++ lib.optionals stdenv.hostPlatform.isLinux [ pkgs.bubblewrap pkgs.socat ] @@ -47,7 +81,8 @@ pkgs.buildNpmPackage (finalAttrs: { description = "Agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster"; homepage = "https://github.com/anthropics/claude-code"; downloadPage = "https://www.npmjs.com/package/@anthropic-ai/claude-code"; - license = pkgs.lib.licenses.unfree; + license = lib.licenses.unfree; mainProgram = "claude"; + platforms = lib.attrNames sources; }; -}) +} diff --git a/packages/claude-code/update.sh b/packages/claude-code/update.sh index 2e307c8..72f7098 100755 --- a/packages/claude-code/update.sh +++ b/packages/claude-code/update.sh @@ -1,17 +1,18 @@ #!/usr/bin/env nix-shell -#!nix-shell -i bash -p curl jq nodejs prefetch-npm-deps nix-prefetch +#!nix-shell -i bash -p curl jq nix # shellcheck shell=bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" PKG_FILE="$SCRIPT_DIR/package.nix" -LOCK_FILE="$SCRIPT_DIR/package-lock.json" -cd "$ROOT_DIR" +# keep in sync with the `sources` attrset in package.nix +PLATFORMS=(linux-x64 linux-arm64 darwin-x64 darwin-arm64) -extract_hash() { - sed 's/\x1b\[[0-9;]*m//g' | grep 'got:' | tail -1 | grep -oP 'sha256-[A-Za-z0-9+/]+=' +prefetch() { + local url="$1" + nix --extra-experimental-features 'nix-command flakes' \ + store prefetch-file --unpack --json "$url" 2>/dev/null | jq -r '.hash' } main() { @@ -27,35 +28,24 @@ main() { echo "updating claude-code: $current -> $latest" - local url="https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-${latest}.tgz" - - echo " prefetching source..." - local base32 src_hash - base32=$(nix-prefetch-url --unpack "$url" 2>/dev/null) - src_hash=$(nix hash convert --to sri "sha256:$base32") - echo " source: $src_hash" - - echo " generating package-lock.json..." - local tmpdir - tmpdir=$(mktemp -d) - trap 'rm -rf "$tmpdir"' RETURN - curl -sf "$url" -o "$tmpdir/pkg.tgz" - tar xzf "$tmpdir/pkg.tgz" -C "$tmpdir" --strip-components=1 - (cd "$tmpdir" && npm install --package-lock-only --ignore-scripts --no-audit --no-fund 2>/dev/null) - cp "$tmpdir/package-lock.json" "$LOCK_FILE" - - echo " computing npm deps hash..." - local npm_hash - npm_hash=$(prefetch-npm-deps "$LOCK_FILE" 2>/dev/null) - echo " npmDepsHash: $npm_hash" - - local old_src old_npm - old_src=$(grep 'hash = "sha256-' "$PKG_FILE" | head -1 | grep -oP 'sha256-[A-Za-z0-9+/]+=') - old_npm=$(grep 'npmDepsHash = "sha256-' "$PKG_FILE" | grep -oP 'sha256-[A-Za-z0-9+/]+=') - sed -i "s|version = \"$current\"|version = \"$latest\"|" "$PKG_FILE" - sed -i "s|$old_src|$src_hash|" "$PKG_FILE" - sed -i "s|$old_npm|$npm_hash|" "$PKG_FILE" + + local slug url new_hash old_hash + for slug in "${PLATFORMS[@]}"; do + url="https://registry.npmjs.org/@anthropic-ai/claude-code-${slug}/-/claude-code-${slug}-${latest}.tgz" + echo " prefetching $slug..." + new_hash=$(prefetch "$url") + old_hash=$(awk -v slug="$slug" ' + $0 ~ "slug = \"" slug "\";" { found=1; next } + found && /hash = "sha256-/ { + match($0, /sha256-[A-Za-z0-9+\/]+=*/) + print substr($0, RSTART, RLENGTH) + exit + } + ' "$PKG_FILE") + sed -i "s|$old_hash|$new_hash|" "$PKG_FILE" + echo " $new_hash" + done echo "claude-code updated to $latest" }