7eefb09314
`nix/devShell.nix` collected `devShellHook` by scanning every package:
nonNpmHooks = map (p: p.passthru.devShellHook or "") packages;
But `minimal` and `messaging` are `.override` variants of `default`, so
each carries its own `devShellHook` exporting its own HERMES_PYTHON. The
scan therefore concatenated three conflicting exports and forced Nix to
evaluate and realise three separate uv2nix editable venvs on every
`nix develop`.
`attrValues` is alphabetical, so the last hook won (`minimal`) while
`python`/VIRTUAL_ENV came from `default`'s devDeps:
HERMES_PYTHON = ...dimim2... (minimal — no optional deps)
python / VIRTUAL_ENV = ...85r28... (full)
Inside the shell `$HERMES_PYTHON -c "import anthropic"` failed while
`python -c "import anthropic"` succeeded. Worse, `scripts/run_tests.sh`
prefers HERMES_PYTHON, so the suite ran against the minimal venv. Its
guard did not catch this: it only checks that HERMES_PYTHON has pytest,
and minimal's venv does (pytest is in the `dev` group), so the wrong
interpreter was silently accepted.
Tying the hook to `packages.default` — the same package whose `devDeps`
are installed — keeps HERMES_PYTHON, `python`, and VIRTUAL_ENV pointing
at one venv by construction.
editable venvs referenced 3 -> 1
their combined closure 421 MB -> 140 MB
test failures 85 -> 32
The venv mismatch was masking 53 failures; e.g. test_web_tools_config.py
goes 2-failed -> 38-passed. Full suite is now 25369 passed / 32 failed,
and those 32 reproduce identically on a pristine HEAD worktree with no
nix/ changes under the same interpreter (mostly NixOS artifacts — tests
spawning bare `python3` in a scrubbed env exit 127).
68 lines
2.6 KiB
Nix
68 lines
2.6 KiB
Nix
# nix/devShell.nix — Dev shell that delegates setup to each package
|
|
#
|
|
# Each npm workspace package exposes passthru.packageJsonPath (e.g.
|
|
# "ui-tui/package.json"). This file collects them all and passes the
|
|
# list to mkNpmDevShellHook, which stamps all package.jsons at once,
|
|
# then runs a single `npm i --package-lock-only` if any changed and
|
|
# `npm ci` if the lockfile changed.
|
|
{ ... }:
|
|
{
|
|
perSystem =
|
|
{ pkgs, self', ... }:
|
|
let
|
|
packages = builtins.attrValues self'.packages;
|
|
hermesNpmLib = self'.packages.default.passthru.hermesNpmLib;
|
|
|
|
# Collect all packageJsonPath values from npm workspace packages.
|
|
npmPackageJsonPaths = builtins.filter (p: p != null) (
|
|
map (p: p.passthru.packageJsonPath or null) packages
|
|
);
|
|
|
|
hermesAgentDevShellHook = self'.packages.default.passthru.devShellHook;
|
|
in
|
|
{
|
|
devShells.default = pkgs.mkShell {
|
|
packages = with pkgs; [
|
|
(pkgs.runCommand "hermes" { } ''
|
|
mkdir -p $out/bin
|
|
install -Dm755 ${../hermes} $out/bin/hermes
|
|
'')
|
|
(pkgs.runCommand "dev-sandbox" { } ''
|
|
mkdir -p $out/bin
|
|
install -Dm755 ${../scripts/dev-sandbox.sh} $out/bin/sandbox
|
|
'')
|
|
uv
|
|
# Headless Wayland compositor for E2E tests (test:e2e:visual).
|
|
# cage renders a single client with no window management, so
|
|
# the Electron window opens at a fixed size without tiling.
|
|
# libglvnd provides libEGL.so.1 that cage needs on NixOS.
|
|
cage
|
|
libglvnd
|
|
# Graphical terminal + Wayland screenshot client for CLI/TUI UI
|
|
# evidence. `cage -- ghostty ...` keeps captures off the user's
|
|
# live compositor; grim runs inside that isolated client session.
|
|
ghostty
|
|
grim
|
|
]
|
|
++ self'.packages.default.passthru.devDeps;
|
|
shellHook = ''
|
|
${hermesAgentDevShellHook}
|
|
${hermesNpmLib.mkNpmDevShellHook npmPackageJsonPaths}
|
|
|
|
# Force Node to use Nix's playwright-test binary instead of node_modules/.bin
|
|
export PATH="${pkgs.playwright-test}/bin:$PATH"
|
|
|
|
# for the devshell to pick up the src
|
|
export HERMES_PYTHON_SRC_ROOT=$(git rev-parse --show-toplevel)
|
|
|
|
# Let `uv run --active --no-sync` reuse Nix's provisioned Python
|
|
# environment instead of creating an empty project .venv.
|
|
export VIRTUAL_ENV="$(dirname "$(dirname "$(readlink -f "$(command -v python)")")")"
|
|
|
|
echo "Hermes Agent dev shell in $HERMES_PYTHON_SRC_ROOT"
|
|
echo "Ready. Run 'hermes' or 'sandbox hermes' to start."
|
|
'';
|
|
};
|
|
};
|
|
}
|