From f292ca58435fa87ea3f8c396359dc113fc10acf9 Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:04:13 +0000 Subject: [PATCH 1/8] feat(nix): add package build derivation for tarball generation Add packages.default derivation to flake.nix that builds the npm package tarball using pnpm_10.fetchDeps for reproducible builds. - Use stdenv.mkDerivation with pnpm_10.configHook - Fetch dependencies with fixed hash for reproducibility - Run pnpm build and pnpm pack in buildPhase/installPhase - Output tarball to $out directory This enables `nix build` to generate a reproducible tarball that can be used for npm publishing, ensuring consistent builds across CI and local environments. --- flake.nix | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/flake.nix b/flake.nix index e953f20..96e4528 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,42 @@ perSystem = { pkgs, ... }: { + packages.default = + let + packageJson = builtins.fromJSON (builtins.readFile ./package.json); + in + pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "stackone-ai"; + version = packageJson.version; + + src = ./.; + + nativeBuildInputs = with pkgs; [ + nodejs_24 + pnpm_10 + pnpm_10.configHook + ]; + + pnpmDeps = pkgs.pnpm_10.fetchDeps { + inherit (finalAttrs) pname version src; + hash = "sha256-GDY7RZUl6A0d3l8Rz6X1sHQfwHgM2GKpcJ65yAKOmrg="; + fetcherVersion = 1; + }; + + buildPhase = '' + runHook preBuild + pnpm run build + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out + pnpm pack --pack-destination $out + runHook postInstall + ''; + }); + devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ # runtime From 7900b6adc6607e6a8a119faf89dc0b14c9f67400 Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:04:23 +0000 Subject: [PATCH 2/8] chore(hooks): add pre-commit hook for pnpm deps hash update Add script and lefthook configuration to automatically update the pnpm deps hash in flake.nix when pnpm-lock.yaml changes. - Add scripts/update-pnpm-hash.sh to calculate and update hash - Configure lefthook to run script on pnpm-lock.yaml changes - Auto-stage updated flake.nix after hash update This ensures the Nix build remains functional after dependency updates without manual hash maintenance. --- lefthook.yaml | 4 ++++ scripts/update-pnpm-hash.sh | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100755 scripts/update-pnpm-hash.sh diff --git a/lefthook.yaml b/lefthook.yaml index 21bf81b..699d848 100644 --- a/lefthook.yaml +++ b/lefthook.yaml @@ -13,6 +13,10 @@ pre-commit: glob: '*.nix' run: nix develop --command nixfmt {staged_files} stage_fixed: true + - name: update-pnpm-hash + glob: 'pnpm-lock.yaml' + run: ./scripts/update-pnpm-hash.sh + stage_fixed: true pre-push: jobs: diff --git a/scripts/update-pnpm-hash.sh b/scripts/update-pnpm-hash.sh new file mode 100755 index 0000000..45d8be3 --- /dev/null +++ b/scripts/update-pnpm-hash.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Update pnpm deps hash in flake.nix +# This script runs nix build to get the correct hash and updates flake.nix + +FLAKE_FILE="flake.nix" + +# Check if flake.nix exists +if [[ ! -f "$FLAKE_FILE" ]]; then + echo "Error: $FLAKE_FILE not found" + exit 1 +fi + +# Run nix build and capture the output +echo "Calculating pnpm deps hash..." +OUTPUT=$(nix build --no-link 2>&1 || true) + +# Check if there's a hash mismatch +if echo "$OUTPUT" | grep -q "hash mismatch"; then + # Extract the new hash + NEW_HASH=$(echo "$OUTPUT" | grep "got:" | sed 's/.*got:[[:space:]]*//' | tr -d '[:space:]') + + if [[ -z "$NEW_HASH" ]]; then + echo "Error: Could not extract new hash" + exit 1 + fi + + echo "New hash: $NEW_HASH" + + # Update the hash in flake.nix (simple pattern for the hash line) + sed -i.bak "s|hash = \"sha256-[^\"]*\"|hash = \"${NEW_HASH}\"|" "$FLAKE_FILE" + rm -f "${FLAKE_FILE}.bak" + + echo "Updated $FLAKE_FILE with new hash" +else + echo "Hash is up to date" +fi From c8766bb5dff35d51eb846d1a497ad76d8d598b6d Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:04:30 +0000 Subject: [PATCH 3/8] ci(publish): use nix build for package tarball generation Update release and dry-publish workflows to use `nix build` instead of `pnpm pack` for generating package tarballs. - release.yaml: Build with nix, publish from result/*.tgz - dry-publish.yaml: Build with nix, pass tarball to pkg-pr-new This ensures CI uses the same reproducible build process as local development, improving build consistency and reliability. --- .github/workflows/dry-publish.yaml | 5 ++++- .github/workflows/release.yaml | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dry-publish.yaml b/.github/workflows/dry-publish.yaml index a8468b5..bc6fd00 100644 --- a/.github/workflows/dry-publish.yaml +++ b/.github/workflows/dry-publish.yaml @@ -13,5 +13,8 @@ jobs: - name: Setup Nix uses: ./.github/actions/setup-nix + - name: 📦 Build package + run: nix build + - name: 🚀 Dry Run Publish Package - run: nix develop --command pnpm dlx pkg-pr-new publish --pnpm + run: nix develop --command pnpm dlx pkg-pr-new publish result/*.tgz diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 802525c..33eafd9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -41,12 +41,12 @@ jobs: registry-url: 'https://registry.npmjs.org' node-version: lts/* - - name: 📦 Pack package - run: nix develop --command pnpm pack + - name: 📦 Build package + run: nix build - name: 🚀 Publish package shell: bash run: | - PACKAGE_TGZ=$(ls *.tgz | head -n 1) + PACKAGE_TGZ=$(ls result/*.tgz | head -n 1) echo "Publishing package: $PACKAGE_TGZ" npm publish "$PACKAGE_TGZ" --access public From 8b443b3cf1df4574659e1e5c27bf0d625d250e2e Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:04:35 +0000 Subject: [PATCH 4/8] chore(git): ignore nix build result symlink --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ca35cce..5d06827 100644 --- a/.gitignore +++ b/.gitignore @@ -181,3 +181,4 @@ dist .direnv !.envrc +result From 38078e9fd3b10c39a11a925d88aaf92ad11e64d8 Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:04:48 +0000 Subject: [PATCH 5/8] ci: split build-and-test into separate build and test jobs Separate the combined build-and-test job into distinct jobs: - build: Uses nix build for reproducible package generation - test: Runs pnpm test in nix develop shell This allows build and test to run in parallel and makes it clearer which step failed when issues occur. --- .github/workflows/ci.yaml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ba9c41f..2498019 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,7 +38,7 @@ jobs: - name: Run Lint run: nix develop --command pnpm run lint - build-and-test: + build: runs-on: ubuntu-latest steps: - name: Checkout repository @@ -47,8 +47,17 @@ jobs: - name: Setup Nix uses: ./.github/actions/setup-nix - - name: Run Build - run: nix develop --command pnpm run build + - name: Build package + run: nix build + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Setup Nix + uses: ./.github/actions/setup-nix - name: Run Tests run: nix develop --command pnpm test From ffce38e78f82946b574e669e8707bc4de586336d Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:04:54 +0000 Subject: [PATCH 6/8] chore(package): remove preinstall only-allow pnpm check Remove the preinstall script that enforces pnpm usage. This check is unnecessary as the project uses nix develop which provides the correct pnpm version, and it can cause issues in CI environments. --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 478f334..e4f0b9c 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "lint:oxfmt": "oxfmt --no-error-on-unmatched-pattern --check .", "lint:oxlint": "oxlint --max-warnings=0 --type-aware --type-check", "lint:knip": "knip", - "preinstall": "npx only-allow pnpm", "prepack": "npm pkg delete scripts.preinstall && pnpm run build", "test": "vitest", "coverage": "vitest run --coverage" From 39eca4ca79515ee1533fa84a300c8b19e1b141e7 Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:08:07 +0000 Subject: [PATCH 7/8] fix(nix): use system-specific hashes for pnpm deps Different platforms download different platform-specific npm packages (e.g., darwin-arm64 vs linux-x64 binaries), resulting in different hashes for pnpm deps. - Add pnpmDepsHash map with per-system hashes - Update hash script to detect current system and update only that hash - Add hashes for x86_64-linux (CI) and aarch64-darwin (local dev) --- flake.nix | 9 +++++++-- scripts/update-pnpm-hash.sh | 16 ++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/flake.nix b/flake.nix index 96e4528..b77eca4 100644 --- a/flake.nix +++ b/flake.nix @@ -16,11 +16,16 @@ ]; perSystem = - { pkgs, ... }: + { pkgs, system, ... }: { packages.default = let packageJson = builtins.fromJSON (builtins.readFile ./package.json); + pnpmDepsHash = { + x86_64-linux = "sha256-PrCGXf5r03gfsoGJAzew592Al1G5dx6xa/qFxazuqUo="; + aarch64-linux = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + aarch64-darwin = "sha256-GDY7RZUl6A0d3l8Rz6X1sHQfwHgM2GKpcJ65yAKOmrg="; + }; in pkgs.stdenv.mkDerivation (finalAttrs: { pname = "stackone-ai"; @@ -36,7 +41,7 @@ pnpmDeps = pkgs.pnpm_10.fetchDeps { inherit (finalAttrs) pname version src; - hash = "sha256-GDY7RZUl6A0d3l8Rz6X1sHQfwHgM2GKpcJ65yAKOmrg="; + hash = pnpmDepsHash.${system}; fetcherVersion = 1; }; diff --git a/scripts/update-pnpm-hash.sh b/scripts/update-pnpm-hash.sh index 45d8be3..d6e005b 100755 --- a/scripts/update-pnpm-hash.sh +++ b/scripts/update-pnpm-hash.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -# Update pnpm deps hash in flake.nix +# Update pnpm deps hash in flake.nix for the current system # This script runs nix build to get the correct hash and updates flake.nix FLAKE_FILE="flake.nix" @@ -12,6 +12,10 @@ if [[ ! -f "$FLAKE_FILE" ]]; then exit 1 fi +# Detect current system +SYSTEM=$(nix eval --impure --raw --expr 'builtins.currentSystem') +echo "Current system: $SYSTEM" + # Run nix build and capture the output echo "Calculating pnpm deps hash..." OUTPUT=$(nix build --no-link 2>&1 || true) @@ -26,13 +30,13 @@ if echo "$OUTPUT" | grep -q "hash mismatch"; then exit 1 fi - echo "New hash: $NEW_HASH" + echo "New hash for $SYSTEM: $NEW_HASH" - # Update the hash in flake.nix (simple pattern for the hash line) - sed -i.bak "s|hash = \"sha256-[^\"]*\"|hash = \"${NEW_HASH}\"|" "$FLAKE_FILE" + # Update the hash for current system in flake.nix + sed -i.bak "s|${SYSTEM} = \"sha256-[^\"]*\"|${SYSTEM} = \"${NEW_HASH}\"|" "$FLAKE_FILE" rm -f "${FLAKE_FILE}.bak" - echo "Updated $FLAKE_FILE with new hash" + echo "Updated $FLAKE_FILE with new hash for $SYSTEM" else - echo "Hash is up to date" + echo "Hash is up to date for $SYSTEM" fi From 5878e774235666d5451c7fe2d06ffb2dab0ac5ae Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Sun, 21 Dec 2025 12:10:42 +0000 Subject: [PATCH 8/8] ci: add --print-build-logs and revert dry-publish - Add --print-build-logs to nix build for better CI visibility - Revert dry-publish to use pnpm directly as pkg-pr-new doesn't support pre-built tarballs --- .github/workflows/ci.yaml | 2 +- .github/workflows/dry-publish.yaml | 5 +---- .github/workflows/release.yaml | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2498019..235a49e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -48,7 +48,7 @@ jobs: uses: ./.github/actions/setup-nix - name: Build package - run: nix build + run: nix build --print-build-logs test: runs-on: ubuntu-latest diff --git a/.github/workflows/dry-publish.yaml b/.github/workflows/dry-publish.yaml index bc6fd00..a8468b5 100644 --- a/.github/workflows/dry-publish.yaml +++ b/.github/workflows/dry-publish.yaml @@ -13,8 +13,5 @@ jobs: - name: Setup Nix uses: ./.github/actions/setup-nix - - name: 📦 Build package - run: nix build - - name: 🚀 Dry Run Publish Package - run: nix develop --command pnpm dlx pkg-pr-new publish result/*.tgz + run: nix develop --command pnpm dlx pkg-pr-new publish --pnpm diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 33eafd9..34f51ae 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -42,7 +42,7 @@ jobs: node-version: lts/* - name: 📦 Build package - run: nix build + run: nix build --print-build-logs - name: 🚀 Publish package shell: bash