diff --git a/flake.nix b/flake.nix index f3a1fc15..4414f67e 100644 --- a/flake.nix +++ b/flake.nix @@ -6,8 +6,14 @@ flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = nixpkgs.legacyPackages.${system}; @@ -27,15 +33,25 @@ nativeBuildInputs = [ pkgs.bun pkgs.makeWrapper - pkgs.python3 # needed by node-gyp to compile better-sqlite3 - ] ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin [ - pkgs.darwin.cctools # provides libtool needed by node-gyp on macOS + pkgs.python3 # needed by node-gyp to compile better-sqlite3 + ] + ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin [ + pkgs.darwin.cctools # provides libtool needed by node-gyp on macOS ]; buildInputs = [ pkgs.sqlite ]; + dontConfigure = true; + buildPhase = '' export HOME=$(mktemp -d) + # Copy pre-downloaded deps, then fix shebangs and run install scripts + cp -r ${bunDeps}/node_modules node_modules + chmod -R u+w node_modules + patchShebangs node_modules + + # Run lifecycle scripts (e.g. better-sqlite3 native compilation) + # without allowing bun to reach the network. bun install --frozen-lockfile ''; @@ -60,6 +76,36 @@ platforms = platforms.unix; }; }; + + # Fixed-output derivation: download deps only (no lifecycle scripts). + # FODs get network access because the output is content-addressed. + # --ignore-scripts avoids native compilation, which would introduce + # Nix store references that FODs are not allowed to contain. + bunDeps = pkgs.stdenv.mkDerivation { + pname = "qmd-deps"; + version = "1.0.0"; + + src = ./.; + + nativeBuildInputs = [ pkgs.bun ]; + + dontConfigure = true; + dontFixup = true; + + buildPhase = '' + export HOME=$(mktemp -d) + bun install --frozen-lockfile --ignore-scripts + ''; + + installPhase = '' + mkdir -p $out + cp -r node_modules $out/node_modules + ''; + + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + outputHash = "sha256-gfQmBdLdapDsZrG3QjoBvCNmzuTx4ek7l7Vi26z1Vbc="; + }; in { packages = { diff --git a/package.json b/package.json index 2341cd20..cc339db3 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "vsearch": "tsx src/qmd.ts vsearch", "rerank": "tsx src/qmd.ts rerank", "inspector": "npx @modelcontextprotocol/inspector tsx src/qmd.ts mcp", - "release": "./scripts/release.sh" + "release": "./scripts/release.sh", + "update-flake-hash": "./scripts/update-flake-hash.sh" }, "publishConfig": { "access": "public" diff --git a/scripts/update-flake-hash.sh b/scripts/update-flake-hash.sh new file mode 100755 index 00000000..fb8ef6c7 --- /dev/null +++ b/scripts/update-flake-hash.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Recompute the Bun dependency hash in flake.nix after bun.lock changes. +# +# Usage: ./scripts/update-flake-hash.sh +# +# How it works: +# 1. Temporarily sets the outputHash to a known-wrong value +# 2. Runs `nix build`, which fails but prints the correct hash +# 3. Patches the correct hash back into flake.nix +# +# Requires: nix with flakes enabled, sed, grep + +set -uo pipefail + +FLAKE="flake.nix" +FAKE_HASH="sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + +# 1. Replace current hash with a known-wrong one +sed -i 's|outputHash = "sha256-[^"]*";|outputHash = "'"$FAKE_HASH"'";|' "$FLAKE" + +echo "Computing dependency hash (this will download deps in a sandbox)..." + +# 2. Build and capture the expected hash from the error output. +# nix build will exit non-zero (hash mismatch), which is expected. +BUILD_OUTPUT=$(nix build 2>&1 || true) +HASH=$(echo "$BUILD_OUTPUT" | grep -oP 'got:\s+\Ksha256-[A-Za-z0-9+/]+=*' | head -1) + +if [ -z "$HASH" ]; then + echo "ERROR: could not extract hash from nix build output." >&2 + echo "" >&2 + echo "nix build output:" >&2 + echo "$BUILD_OUTPUT" >&2 + # Restore the fake hash so it's obvious something went wrong + exit 1 +fi + +# 3. Write the real hash back +sed -i 's|outputHash = "'"$FAKE_HASH"'";|outputHash = "'"$HASH"'";|' "$FLAKE" + +echo "Updated flake.nix with hash: $HASH"