diff --git a/.claude/tasks/0002-flake-outputs.md b/.claude/tasks/0002-flake-outputs.md new file mode 100644 index 0000000..42824a6 --- /dev/null +++ b/.claude/tasks/0002-flake-outputs.md @@ -0,0 +1,52 @@ +--- +spec: nix-flake-packaging +blocked-by: 0001-flake-build +--- + +## What to build + +The remaining flake outputs layered onto the working build: a runnable app, a development shell, direnv auto-loading, and a checks set that gates the project reproducibly. + +The default app points at the compiled binary so the CLI runs without a prior install. +The default dev shell exposes the same pinned Bun as the build plus biome, and a `use flake` direnv configuration loads it automatically on entering the directory. +The checks set aggregates the Bun test tiers, a build-seam smoke check that invokes the built binary (for example `--help`) and asserts a zero exit, and biome lint run through the treefmt-nix flake-parts module sharing the existing biome configuration. + +## Acceptance criteria + +- [x] `nix run` executes the CLI without a prior install. +- [x] `nix develop` drops into a shell exposing the pinned Bun and biome at their expected versions. +- [x] The dev shell's Bun version is the same pin the build derivation uses. +- [x] A `use flake` `.envrc` auto-loads the dev shell for direnv users. +- [x] `nix flake check` runs the Bun test tiers, the build-seam smoke check against the Nix-built binary, and biome lint via treefmt-nix. + +## Implementation Notes + +All five criteria were verified end-to-end: `nix run` exits 0, `nix develop` exposes Bun 1.3.13, biome 2.5.4, and bun2nix, and `nix flake check` runs all three checks green. + +### Outputs + +The default app points at the compiled binary via its store path. +The dev shell carries the pinned Bun, biome, and bun2nix — bun2nix so the repo's `postinstall` regeneration of `bun.nix` works inside the shell. +`.envrc` is a one-line `use flake`, and `.direnv/` is gitignored. + +### Bun pin sameness + +The dev shell takes Bun from `inputs.nixpkgs-bun` directly, while the build takes it through bun2nix, whose nixpkgs `follows` the same `nixpkgs-bun`. +Both therefore resolve to the one pinned input, which is the single source of the Bun version. +The value is not threaded through a shared binding because bun2nix bakes its own `pkgs.bun` into its build hook, so the compile-side Bun cannot be passed in — the shared `nixpkgs-bun` input is the seam instead. + +### Checks + +`tests` runs `bun test` across the workspace through bun2nix's check phase. +`smoke` runs the Nix-built binary with `--help` and asserts a zero exit; while the CLI is still a placeholder this passes for any argument, and it will exercise real `--help` once the CLI lands. +Biome runs through the treefmt-nix flake-parts module, which auto-adds its own check. + +### Biome via treefmt-nix + +The treefmt biome program reads the repo's `biome.json` (via `importJSON`) so there is one configuration, but with `vcs.enabled` overridden off: the reproducible check has no git tree, and biome's `useIgnoreFile` lookup errors without one, while treefmt already selects the files. +Schema validation is skipped because nixpkgs' biome is newer than the schema treefmt-nix would validate against, and the config is the one biome itself runs with. + +### Deviation + +`packages/core/src/index_test.ts` was reformatted by biome (two `test.todo` lines exceeded the repo's `lineWidth`). +This is a pre-existing file, formatted only to make the new lint gate green — a necessary consequence of adding the gate, not a change of its behaviour. diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 09295f6..69ae774 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ packages/bin/kitchen result result-* +# direnv / nix-direnv cache +.direnv/ + # local environment overrides .env .env.local diff --git a/flake.lock b/flake.lock index 3d8bda3..4c4b36d 100644 --- a/flake.lock +++ b/flake.lock @@ -118,7 +118,8 @@ "flake-parts": "flake-parts_2", "nixpkgs": "nixpkgs", "nixpkgs-bun": "nixpkgs-bun", - "systems": "systems" + "systems": "systems", + "treefmt-nix": "treefmt-nix_2" } }, "systems": { @@ -156,6 +157,26 @@ "repo": "treefmt-nix", "type": "github" } + }, + "treefmt-nix_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784369104, + "narHash": "sha256-47cxbcZODibHv3rELFQ9vZly0vUNkND/atn/U7HLeb0=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "df3c0640565d04a0261253cdd89fce78ec50168a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 69691bb..a472f58 100644 --- a/flake.nix +++ b/flake.nix @@ -4,9 +4,9 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; - # Provides the single pinned Bun used to compile the binary, held apart - # from `nixpkgs` so a `nixpkgs` update cannot drag Bun to a release that - # emits empty binaries under sandboxed native compilation. + # The single pinned Bun, used to compile the binary and to develop against. + # It is held apart from `nixpkgs` so a `nixpkgs` update cannot pull in a Bun + # release that emits empty binaries under sandboxed native compilation. nixpkgs-bun.url = "github:nixos/nixpkgs/241313f4e8e508cb9b13278c2b0fa25b9ca27163"; flake-parts.url = "github:hercules-ci/flake-parts"; @@ -19,6 +19,11 @@ inputs.nixpkgs.follows = "nixpkgs-bun"; inputs.systems.follows = "systems"; }; + + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = @@ -26,6 +31,8 @@ inputs.flake-parts.lib.mkFlake { inherit inputs; } { systems = import inputs.systems; + imports = [ inputs.treefmt-nix.flakeModule ]; + perSystem = { system, ... }: let @@ -33,9 +40,65 @@ inherit system; overlays = [ inputs.bun2nix.overlays.default ]; }; + + # The Bun from the same pinned `nixpkgs-bun` the build compiles with. + bun = inputs.nixpkgs-bun.legacyPackages.${system}.bun; + + kitchen = pkgs.callPackage ./package.nix { }; + + bunDeps = pkgs.bun2nix.fetchBunDeps { bunNix = ./bun.nix; }; in { - packages.default = pkgs.callPackage ./package.nix { }; + # Share the overlaid package set with the imported modules. + _module.args.pkgs = pkgs; + + packages.default = kitchen; + + apps.default = { + type = "app"; + program = "${kitchen}/bin/kitchen"; + }; + + devShells.default = pkgs.mkShell { + packages = [ + bun + pkgs.biome + pkgs.bun2nix + ]; + }; + + treefmt = { + projectRootFile = "flake.nix"; + programs.biome = { + enable = true; + # Reuse the repo's biome configuration as the single source. + # The sandboxed check has no git tree, so biome's VCS-ignore + # lookup must be off. + settings = pkgs.lib.recursiveUpdate (pkgs.lib.importJSON ./biome.json) { + vcs.enabled = false; + }; + # Skip re-validating the config; biome consumes it directly. + validate.enable = false; + }; + }; + + checks = { + tests = pkgs.bun2nix.mkDerivation { + pname = "kitchen-tests"; + inherit (kitchen) version; + src = ./.; + inherit bunDeps; + dontRunLifecycleScripts = true; + dontUseBunBuild = true; + doCheck = true; + installPhase = "touch $out"; + }; + + smoke = pkgs.runCommand "kitchen-smoke" { } '' + ${kitchen}/bin/kitchen --help + touch $out + ''; + }; }; }; } diff --git a/packages/core/src/index_test.ts b/packages/core/src/index_test.ts index 3937ea6..ddd8f6b 100644 --- a/packages/core/src/index_test.ts +++ b/packages/core/src/index_test.ts @@ -36,8 +36,12 @@ describe("parser", () => { }); describe("raw fallbacks", () => { - test.todo("preserves an unmodelled block (e.g. a GFM table) as a RawBlock with verbatim source"); - test.todo("preserves an unmodelled inline (e.g. strikethrough) as a RawInline with verbatim source"); + test.todo( + "preserves an unmodelled block (e.g. a GFM table) as a RawBlock with verbatim source", + ); + test.todo( + "preserves an unmodelled inline (e.g. strikethrough) as a RawInline with verbatim source", + ); }); describe("ingredient annotations", () => {