{ description = "Maestro — terminal-session orchestrator for one machine"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; crane.url = "github:ipetkov/crane"; }; outputs = inputs@{ flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } { systems = [ "x86_64-linux" "aarch64-linux" ]; imports = [ ./nix/home-manager-module.nix ]; perSystem = { lib, pkgs, self', ... }: let craneLib = inputs.crane.mkLib pkgs; version = (lib.importTOML ./Cargo.toml).workspace.package.version; # Cargo source filtering keeps only *.rs, *.toml and Cargo.lock. The # SPA is built separately (below) and handed to the Rust build as a # path, so nothing under web/ needs to be in this source tree. commonArgs = { src = craneLib.cleanCargoSource ./.; inherit version; strictDeps = true; # rustls everywhere (reqwest, tokio-tungstenite): no openssl, no # pkg-config, nothing to link against. buildInputs = [ ]; nativeBuildInputs = [ ]; }; cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { pname = "maestro-workspace"; }); # Runtime dependencies the daemon shells out to. Suffixed onto PATH so # a user's own tmux/git still wins inside spawned sessions. runtimeDeps = [ pkgs.tmux pkgs.git ]; maestro = craneLib.buildPackage ( commonArgs // { inherit cargoArtifacts; pname = "maestro"; cargoExtraArgs = "--package maestro"; doCheck = false; nativeBuildInputs = commonArgs.nativeBuildInputs ++ [ pkgs.makeWrapper ]; postInstall = '' wrapProgram $out/bin/maestro \ --suffix PATH : ${lib.makeBinPath runtimeDeps} ''; meta = { description = "Unified maestro binary: CLI + per-host daemon + TUI"; homepage = "https://git.naps.pt/naps62/maestro"; license = lib.licenses.mit; platforms = lib.platforms.linux; mainProgram = "maestro"; }; } ); # The SPA, built on its own so the Rust build never needs node or a # network fetch. `pnpm.fetchDeps` pins the store from pnpm-lock.yaml; # bump `hash` whenever that lockfile changes (set it to # lib.fakeHash, build, copy the `got:` value). webFrontend = pkgs.stdenv.mkDerivation (finalAttrs: { pname = "maestro-web-frontend"; inherit version; src = ./web; nativeBuildInputs = [ pkgs.nodejs # pnpm 10, not the default 11: web/pnpm-lock.yaml is # lockfileVersion 9.0, and package.json pins pnpm@9.15.4. pkgs.pnpm_10 (pkgs.pnpmConfigHook.override { pnpm = pkgs.pnpm_10; }) ]; pnpmDeps = (pkgs.fetchPnpmDeps.override { pnpm = pkgs.pnpm_10; }) { inherit (finalAttrs) pname version src; fetcherVersion = 3; hash = "sha256-Lhi41AtCK69SM4+7zih19+Njf7o2hyXrAV0W6VO9YxU="; }; buildPhase = '' runHook preBuild pnpm build runHook postBuild ''; # $out IS the bundle directory — that is what MAESTRO_WEB_DIST and # `include_dir!` expect, so index.html sits at its root. installPhase = '' runHook preInstall cp -r dist $out runHook postInstall ''; meta = { description = "Maestro browser SPA bundle"; license = lib.licenses.mit; }; }); maestro-web = craneLib.buildPackage ( commonArgs // { inherit cargoArtifacts; pname = "maestro-web"; cargoExtraArgs = "--package maestro-web"; doCheck = false; # Skips pnpm entirely in build.rs and embeds this bundle as-is. MAESTRO_WEB_DIST = webFrontend; meta = { description = "Maestro web UI: serves the SPA and proxies to a co-located daemon"; homepage = "https://git.naps.pt/naps62/maestro"; license = lib.licenses.mit; platforms = lib.platforms.linux; mainProgram = "maestro-web"; }; } ); in { packages = { default = maestro; inherit maestro maestro-web webFrontend; }; checks = { inherit maestro maestro-web; maestro-fmt = craneLib.cargoFmt { inherit (commonArgs) src; }; maestro-clippy = craneLib.cargoClippy ( commonArgs // { inherit cargoArtifacts; pname = "maestro-clippy"; # maestro-web is excluded: clippy on it would run build.rs, and # a workspace-wide MAESTRO_WEB_DIST would make every other # crate's cache key depend on the frontend. `checks.maestro-web` # already compiles it. cargoClippyExtraArgs = "--workspace --exclude maestro-web --all-targets -- --deny warnings"; } ); }; devShells.default = craneLib.devShell { inherit (self') checks; packages = [ pkgs.rust-analyzer pkgs.tmux pkgs.git pkgs.just pkgs.nodejs pkgs.pnpm_10 ]; }; }; }; }