diff --git a/flake.nix b/flake.nix index a4b9e0e7..ff5e149e 100644 --- a/flake.nix +++ b/flake.nix @@ -171,47 +171,51 @@ inherit (nixpkgs) lib; inherit (nixpkgs.lib) nixosSystem; }; - in - { - # Build the workspace binaries without running tests. Tests - # are run as a separate check (`checks.cargo-test`) that - # carries the `hyperhive-assets` build input — `hive-ag3nt:: - # prompt::tests` reads the production prompt template at test - # runtime through `$HIVE_ASSETS_DIR`, so wiring the env var - # into the build phase here would make the prompt's hash a - # build input of `default` (defeats the asset-split cache goal: a - # prompt edit would still bust the binary derivation, even - # though no .rs file changed). Keeping tests in a separate - # check derivation localises the asset-rebuild blast radius - # to that one check — `nix flake check` still exercises them. - default = craneLib.buildPackage { + # Daemon + harness + MCP server binaries. Excludes hivectl and + # hive-forge which are their own derivations below — so each bin + # is compiled exactly once. `packages.default` joins all three + # via symlinkJoin; no binary is compiled more than once regardless + # of which packages the operator builds together. + # + # Tests are kept in the separate `checks.cargo-test` derivation + # (carries the hyperhive-assets build input for the prompt-template + # assertions in hive-ag3nt::prompt::tests). Keeping them out of the + # binary derivations means a prompt edit doesn't bust the cargo cache. + daemonBins = craneLib.buildPackage { + src = cleanSrc; + inherit cargoArtifacts nativeBuildInputs; + cargoExtraArgs = "--bin hive-c0re --bin hive-agent --bin hive-agent-mcp --bin hive-agent-wake --bin hive-bash-daemon --bin hive-bash-mcp --bin hive-matrix-daemon --bin hive-matrix-mcp --bin hive-metric"; + pname = "hyperhive-daemon"; + version = "0.1.0"; + meta.description = "hyperhive daemon + agent harness + bash/matrix MCP servers"; + doCheck = false; + }; + # Operator CLI — ships `hivectl` (with shell completions and the + # `wg` wrapper) without the daemon binaries. Suitable for + # `nix profile install .#hivectl` / `environment.systemPackages + # = [ inputs.hyperhive.packages.${system}.hivectl ]` when the + # operator only wants the admin CLI. Shares `cargoArtifacts` with + # `daemonBins` so there is no double-rustc cost. + hivectlPkg = craneLib.buildPackage { src = cleanSrc; inherit cargoArtifacts; - # `installShellFiles` provides `installShellCompletion` and - # `makeWrapper` provides `wrapProgram` for the postInstall below; - # appended (not in the shared set) so they're build inputs only of - # this binary derivation. + cargoExtraArgs = "--bin hivectl"; + pname = "hivectl"; + version = "0.1.0"; + meta.description = "hyperhive operator CLI"; + doCheck = false; + # `installShellFiles` + `makeWrapper` scoped to this derivation + # only — daemon bins don't need them. nativeBuildInputs = nativeBuildInputs ++ [ pkgs.installShellFiles pkgs.makeWrapper ]; - pname = "hyperhive-workspace"; - version = "0.1.0"; - meta.description = "hyperhive workspace (hive-c0re, hive-ag3nt, hive-root)"; - doCheck = false; - # Ship hivectl shell completions in the package (the binary's own - # `completions ` verb is the single source of truth, so they - # never drift from the actual verbs). Lands at - # `$out/share/{zsh/site-functions,bash-completion,fish}/…`; an - # operator gets working completion as soon as hivectl is in their - # system/user profile with the shell's completion enabled. - # - # Then wrap hivectl with `wireguard-tools` on PATH so its `wg` - # subcommands (`wg init`/`peer`/`status`) work even before the - # WireGuard mesh is configured — `wg init` is the *first* setup - # step, run before `swarm.wireguard.enable` (which would otherwise - # be what pulls wireguard-tools onto the system). Completion - # generation runs first since wrapProgram renames the real binary. + # Ship shell completions (the binary's own `completions ` + # verb is the single source of truth, so they never drift from + # the actual verbs). Wrap with wireguard-tools so `hivectl wg` + # subcommands work before `swarm.wireguard.enable` is set (wg + # init is the very first setup step). Completion generation runs + # before wrapProgram since wrapProgram renames the real binary. postInstall = '' installShellCompletion --cmd hivectl \ --bash <("$out/bin/hivectl" completions bash) \ @@ -221,6 +225,38 @@ --prefix PATH : ${pkgs.wireguard-tools}/bin ''; }; + # Forgejo CLI — ships `hive-forge` without the rest of the + # workspace. Useful for operator workstations / CI environments + # that only need forge access. Shares `cargoArtifacts` with + # `daemonBins`. + hiveForgePkg = craneLib.buildPackage { + src = cleanSrc; + inherit cargoArtifacts nativeBuildInputs; + cargoExtraArgs = "--bin hive-forge"; + pname = "hive-forge"; + version = "0.1.0"; + meta.description = "hyperhive Forgejo CLI"; + doCheck = false; + }; + in + { + # All workspace binaries in one derivation via symlinkJoin. + # Each binary is compiled exactly once (one rustc per bin, all + # sharing `cargoArtifacts`); symlinkJoin assembles the outputs + # without any additional compilation. The NixOS module's + # `pkgs.hyperhive` (= this) and `nix build .#` both land here. + default = pkgs.symlinkJoin { + name = "hyperhive"; + paths = [ + daemonBins + hivectlPkg + hiveForgePkg + ]; + }; + # Per-bin split packages — useful for operator workstations that + # only want the CLI(s) without the daemon binaries. + hivectl = hivectlPkg; + hive-forge = hiveForgePkg; # Bundled browser assets — see ./nix/frontend.nix. Output is # $out/{dashboard,agent}/ which the Rust binaries serve via # tower_http::ServeDir.