From e32ca410850a9c2689c1a985c52134876806e1f6 Mon Sep 17 00:00:00 2001 From: Justin Giancola Date: Mon, 11 May 2026 00:10:32 -0400 Subject: [PATCH 1/4] feat(nix): add package validation and pinned lock regeneration --- .github/workflows/ci.yml | 8 ------ .github/workflows/nix.yml | 56 +++++++++++++++++++++++++++++++++++++ .github/workflows/pr-ci.yml | 8 ------ CHANGELOG.md | 1 + flake.nix | 32 +++++++++++++++++++-- nix/README.md | 23 ++++++++++++--- package.json | 2 +- 7 files changed, 107 insertions(+), 23 deletions(-) create mode 100644 .github/workflows/nix.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d196b38d..0d44e63c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,14 +38,6 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - - name: Verify Nix lockfile is up to date - run: | - bun run nix:update-lock - if ! git diff --exit-code nix/bun.lock.nix; then - echo "::error::Nix lockfile is out of date. Please run 'bun run nix:update-lock' and commit the changes to nix/bun.lock.nix." - exit 1 - fi - - name: Format check run: bun run format:check diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 00000000..a50fe449 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,56 @@ +name: Nix + +on: + pull_request: + paths-ignore: + - "**/*.md" + - "docs/**" + - "assets/**" + - "LICENSE" + push: + branches: + - main + paths-ignore: + - "**/*.md" + - "docs/**" + - "assets/**" + - "LICENSE" + +concurrency: + group: nix-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + package: + name: Package + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install Nix + uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6 + with: + extra_nix_config: | + extra-trusted-substituters = https://nix-community.cachix.org + extra-trusted-public-keys = nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= + + - name: Verify Nix dependency lockfile + run: | + nix run .#update-bun-lock + if ! git diff --exit-code nix/bun.lock.nix; then + echo "::error::Nix lockfile is out of date. Please run 'bun run nix:update-lock' and commit the changes to nix/bun.lock.nix." + exit 1 + fi + + - name: Check flake outputs + run: nix flake check --print-build-logs + + - name: Build Hunk package + run: nix build .#default --print-build-logs + + - name: Smoke test Nix package + run: | + ./result/bin/hunk --version + skill_path="$(./result/bin/hunk skill path)" + test -f "$skill_path" diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml index 6c1723fb..6fd8968e 100644 --- a/.github/workflows/pr-ci.yml +++ b/.github/workflows/pr-ci.yml @@ -81,14 +81,6 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - - name: Verify Nix lockfile is up to date - run: | - bun run nix:update-lock - if ! git diff --exit-code nix/bun.lock.nix; then - echo "::error::Nix lockfile is out of date. Please run 'bun run nix:update-lock' and commit the changes to nix/bun.lock.nix." - exit 1 - fi - - name: Format check run: bun run format:check diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c7e176..1dfc532e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable user-visible changes to Hunk are documented in this file. ### Added - Added Windows x64 prebuilt artifact publishing to the release workflow. +- Added Nix flake app outputs for `nix run` and a named `hunk` package output. ### Changed diff --git a/flake.nix b/flake.nix index f6b0150a..b8066bda 100644 --- a/flake.nix +++ b/flake.nix @@ -33,10 +33,38 @@ pkgs = import nixpkgs { inherit system; }; - in { - default = pkgs.callPackage ./nix/package.nix { + hunk = pkgs.callPackage ./nix/package.nix { bun2nix = bun2nix.packages.${system}.default; }; + in { + inherit hunk; + default = hunk; + } + ); + + apps = forAllSystems ( + system: let + pkgs = import nixpkgs { + inherit system; + }; + updateBunLock = pkgs.writeShellScriptBin "hunk-update-bun-lock" '' + set -euo pipefail + ${bun2nix.packages.${system}.default}/bin/bun2nix -o nix/bun.lock.nix -c ../ "$@" + if [ -s nix/bun.lock.nix ] && [ "$(${pkgs.coreutils}/bin/tail -c 1 nix/bun.lock.nix)" != "" ]; then + printf '\n' >> nix/bun.lock.nix + fi + ''; + in { + default = { + type = "app"; + program = "${self.packages.${system}.hunk}/bin/hunk"; + meta.description = "Run Hunk"; + }; + update-bun-lock = { + type = "app"; + program = "${updateBunLock}/bin/hunk-update-bun-lock"; + meta.description = "Regenerate nix/bun.lock.nix with the flake-pinned bun2nix"; + }; } ); diff --git a/nix/README.md b/nix/README.md index d0a9a40d..19fde858 100644 --- a/nix/README.md +++ b/nix/README.md @@ -22,7 +22,7 @@ Nix users can install Hunk from source instead of using npm. ```nix { environment.systemPackages = [ - inputs.hunk.packages.${pkgs.stdenv.hostPlatform.system}.default + inputs.hunk.packages.${pkgs.stdenv.hostPlatform.system}.hunk ]; } ``` @@ -32,7 +32,7 @@ Or in Home Manager `home.packages`: ```nix { home.packages = [ - inputs.hunk.packages.${pkgs.stdenv.hostPlatform.system}.default + inputs.hunk.packages.${pkgs.stdenv.hostPlatform.system}.hunk ]; } ``` @@ -63,6 +63,14 @@ Hunk provides a Home Manager module to manage both the package and its configura `enableGitIntegration` writes to Home Manager's Git configuration, so it requires Home Manager's Git module to be enabled with `programs.git.enable = true;`. +## Running from a flake + +Run Hunk directly with Nix: + +```bash +nix run github:modem-dev/hunk -- --help +``` + ## Updating Hunk Flake users update Hunk by updating their own pinned `flake.lock` input: @@ -73,8 +81,13 @@ nix flake lock --update-input hunk ## Building using Nix -Simply run `nix build .#packages.{YOUR_SYSTEM}.default` where YOUR_SYSTEM is one of `x86_64-linux`, `x86_64-darwin`, `aarch64-linux` or `aarch64-darwin`. The resulting -Hunk binary will be `./result/bin/hunk`. +Run `nix build` to build the default package for the current system. The resulting Hunk binary will be `./result/bin/hunk`. + +You can also build the named package explicitly: + +```bash +nix build .#hunk +``` ## Maintainer dependency updates @@ -83,3 +96,5 @@ When JavaScript or Bun dependencies change, regenerate the Nix dependency lockfi ```bash bun run nix:update-lock ``` + +This script requires Nix and runs the flake-pinned `bun2nix` version from `flake.lock`. diff --git a/package.json b/package.json index 4f85de56..7dea17ae 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "bench:highlight-prefetch": "bun run benchmarks/highlight-prefetch.ts", "bench:large-stream": "bun run benchmarks/large-stream.ts", "bench:large-stream-profile": "bun run benchmarks/large-stream-profile.ts", - "nix:update-lock": "bunx bun2nix -o nix/bun.lock.nix -c ../" + "nix:update-lock": "nix run .#update-bun-lock" }, "dependencies": { "@pierre/diffs": "^1.1.19", From bcd9013f41414cbac680a4f9f1bd60b63abfad8c Mon Sep 17 00:00:00 2001 From: Justin Giancola Date: Mon, 11 May 2026 00:10:39 -0400 Subject: [PATCH 2/4] chore(deps): pin Bun type definitions --- bun.lock | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bun.lock b/bun.lock index 5af2ced4..bf714d99 100644 --- a/bun.lock +++ b/bun.lock @@ -18,7 +18,7 @@ "@hunk/session-broker-node": "workspace:*", "@opentui/core": "^0.1.88", "@opentui/react": "^0.1.88", - "@types/bun": "latest", + "@types/bun": "1.3.10", "@types/react": "^19.2.14", "@types/ws": "^8.18.1", "lint-staged": "^16.4.0", diff --git a/package.json b/package.json index 7dea17ae..825ae3f5 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "@hunk/session-broker-node": "workspace:*", "@opentui/core": "^0.1.88", "@opentui/react": "^0.1.88", - "@types/bun": "latest", + "@types/bun": "1.3.10", "@types/react": "^19.2.14", "@types/ws": "^8.18.1", "lint-staged": "^16.4.0", From b0cdead0c55945f1ffa497c5d85a240f8bce04cc Mon Sep 17 00:00:00 2001 From: Justin Giancola Date: Mon, 11 May 2026 00:15:41 -0400 Subject: [PATCH 3/4] fix(nix): evaluate all systems in package CI --- .github/workflows/nix.yml | 3 +++ flake.nix | 52 +++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index a50fe449..c7975a69 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -46,6 +46,9 @@ jobs: - name: Check flake outputs run: nix flake check --print-build-logs + - name: Evaluate all supported systems + run: nix flake check --all-systems --no-build + - name: Build Hunk package run: nix build .#default --print-build-logs diff --git a/flake.nix b/flake.nix index b8066bda..a77a3ed7 100644 --- a/flake.nix +++ b/flake.nix @@ -27,8 +27,7 @@ "aarch64-darwin" ]; forAllSystems = lib.genAttrs supportedSystems; - in { - packages = forAllSystems ( + perSystem = forAllSystems ( system: let pkgs = import nixpkgs { inherit system; @@ -36,17 +35,6 @@ hunk = pkgs.callPackage ./nix/package.nix { bun2nix = bun2nix.packages.${system}.default; }; - in { - inherit hunk; - default = hunk; - } - ); - - apps = forAllSystems ( - system: let - pkgs = import nixpkgs { - inherit system; - }; updateBunLock = pkgs.writeShellScriptBin "hunk-update-bun-lock" '' set -euo pipefail ${bun2nix.packages.${system}.default}/bin/bun2nix -o nix/bun.lock.nix -c ../ "$@" @@ -55,28 +43,32 @@ fi ''; in { - default = { - type = "app"; - program = "${self.packages.${system}.hunk}/bin/hunk"; - meta.description = "Run Hunk"; + packages = { + inherit hunk; + default = hunk; }; - update-bun-lock = { - type = "app"; - program = "${updateBunLock}/bin/hunk-update-bun-lock"; - meta.description = "Regenerate nix/bun.lock.nix with the flake-pinned bun2nix"; + apps = { + default = { + type = "app"; + program = "${hunk}/bin/hunk"; + meta.description = "Run Hunk"; + }; + update-bun-lock = { + type = "app"; + program = "${updateBunLock}/bin/hunk-update-bun-lock"; + meta.description = "Regenerate nix/bun.lock.nix with the flake-pinned bun2nix"; + }; }; - } - ); - - devShells = forAllSystems ( - system: let - pkgs = import nixpkgs { - inherit system; + devShells = { + default = pkgs.callPackage ./nix/devShell.nix {}; }; - in { - default = pkgs.callPackage ./nix/devShell.nix {}; } ); + systemOutput = name: lib.mapAttrs (_: value: value.${name}) perSystem; + in { + packages = systemOutput "packages"; + apps = systemOutput "apps"; + devShells = systemOutput "devShells"; homeManagerModules = { hunk = import ./nix/home-manager.nix; From c5e5b1cea0c4c69df50dfa12e1a52e0f87721d44 Mon Sep 17 00:00:00 2001 From: Justin Giancola Date: Mon, 11 May 2026 00:24:23 -0400 Subject: [PATCH 4/4] docs: document Nix lockfile sync for dependency updates --- CONTRIBUTING.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f57cf966..f8d21869 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,6 +87,24 @@ bun run check:prebuilt-pack bun run publish:prebuilt:npm -- --dry-run ``` +## Updating dependencies + +After changing JavaScript or Bun dependencies, regenerate the Nix dependency lockfile so CI stays green: + +```bash +bun install +bun run nix:update-lock +git add bun.lock nix/bun.lock.nix package.json +``` + +The `nix:update-lock` script requires a one-time [Nix install](https://nixos.org/download/): + +```bash +curl -L https://nixos.org/nix/install | sh +``` + +If you don't have Nix installed, CI will catch the drift and a maintainer can push the regenerated lockfile as a follow-up commit. + ## Validation expectations - Rendering changes: run `bun run typecheck`, `bun test`, `bun run test:tty-smoke`, and do one real TTY smoke run on an actual diff.