{ autoPatchelfHook, alsa-lib, bun, bun2nix, cmake, darwin, lib, libopus, libpulseaudio, ninja, pipewire, pkg-config, removeReferencesTo, rustPlatform, rustToolchain, source, stdenv, stdenvNoCC, unzip, # Wayland screencast support links libpipewire, whose runtime closure adds # ~750 MB (gstreamer, ffmpeg, systemd, ...). Official npm/Bazel addons ship # without it, so default to the lean build; opt in via `.override`. withWaylandScreencast ? false, }: let packageJson = lib.importJSON ../packages/coding-agent/package.json; rootPackageJson = lib.importJSON ../package.json; platform = { aarch64-darwin = { addon = "pi_natives.darwin-arm64.node"; nativeLibrary = "libpi_natives.dylib"; }; aarch64-linux = { addon = "pi_natives.linux-arm64.node"; nativeLibrary = "libpi_natives.so"; }; x86_64-darwin = { addon = "pi_natives.darwin-x64-baseline.node"; nativeLibrary = "libpi_natives.dylib"; rustFlags = "-C target-cpu=x86-64-v2"; }; x86_64-linux = { addon = "pi_natives.linux-x64-baseline.node"; nativeLibrary = "libpi_natives.so"; rustFlags = "-C target-cpu=x86-64-v2"; }; } .${stdenv.hostPlatform.system} or (throw "Unsupported OMP platform: ${stdenv.hostPlatform.system}"); patchedDependencies = lib.mapAttrs ( _: patch: source + "/${patch}" ) rootPackageJson.patchedDependencies; patchOverrides = bun2nix.patchedDependenciesToOverrides { inherit patchedDependencies; }; bunRuntimeTemplate = stdenvNoCC.mkDerivation { pname = "omp-bun-runtime-template"; inherit (bun) version; src = bun.src; nativeBuildInputs = [ unzip ]; dontUnpack = true; dontFixup = true; installPhase = '' runHook preInstall unzip -q "$src" install -Dm755 bun-*/bun "$out/libexec/bun" runHook postInstall ''; }; in stdenv.mkDerivation { pname = "omp"; inherit (packageJson) version; src = source; cargoDeps = rustPlatform.importCargoLock { lockFile = ../Cargo.lock; }; bunDeps = bun2nix.fetchBunDeps { bunNix = ./bun.nix; overrides = patchOverrides; }; nativeBuildInputs = [ bun bun2nix.hook cmake ninja pkg-config removeReferencesTo rustPlatform.bindgenHook rustPlatform.cargoSetupHook rustToolchain ] ++ lib.optionals stdenv.hostPlatform.isLinux [ autoPatchelfHook ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.autoSignDarwinBinariesHook ]; # pcre2 is vendored via PCRE2_SYS_STATIC, but opus must link the nixpkgs # library: audiopus_sys' bundled cmake build installs to lib64 while its # link-search hardcodes lib, so the pkg-config path is the one that works. # libgcc_s is resolved from the compiler's lib output during autoPatchelf. # All dynamic store paths are pinned into the closure via nix-support (see # installPhase). buildInputs = [ libopus ] ++ lib.optionals stdenv.hostPlatform.isLinux [ stdenv.cc.cc.lib ] ++ lib.optionals withWaylandScreencast [ pipewire ]; strictDeps = true; # Nix builders cannot reliably hardlink cache files into node_modules # (and Darwin's clonefile backend also rejects store permissions). bunInstallFlags = [ "--linker=isolated" "--backend=copyfile" ]; dontConfigure = true; dontRunLifecycleScripts = true; dontUseBunBuild = true; dontUseBunCheck = true; dontUseBunInstall = true; dontStrip = true; env = { CMAKE_POLICY_VERSION_MINIMUM = "3.5"; PCRE2_SYS_STATIC = "1"; SOURCE_DATE_EPOCH = "1"; } // lib.optionalAttrs (platform ? rustFlags) { RUSTFLAGS = platform.rustFlags; } // lib.optionalAttrs stdenv.hostPlatform.isDarwin { BUN_NO_CODESIGN_MACHO_BINARY = "1"; }; buildPhase = '' runHook preBuild echo "Building pi-natives" cargo build --release -p pi-natives ${lib.optionalString withWaylandScreencast "--features wayland-pipewire"} install -Dm755 "target/release/${platform.nativeLibrary}" \ "packages/natives/native/${platform.addon}" ${lib.optionalString stdenv.hostPlatform.isLinux '' # The loader extracts this archived addon at runtime, so fix its # interpreter-independent Nix RPATH before Bun embeds it. autoPatchelf -- "packages/natives/native/${platform.addon}" # pi-voice dlopens libpulse-simple.so.0 / libpulse.so.0 / libasound.so.2 # by bare name; glibc resolves those through the calling object's # RUNPATH, so append the client libraries here. Nothing links them, so # autoPatchelf cannot discover them on its own. patchelf --add-rpath "${ lib.makeLibraryPath [ libpulseaudio alsa-lib ] }" \ "packages/natives/native/${platform.addon}" ''} ${lib.optionalString stdenv.hostPlatform.isDarwin '' # arm64 Darwin requires even locally-built Mach-O addons to carry an # ad-hoc signature. Sign before Bun archives the file. signIfRequired "packages/natives/native/${platform.addon}" ''} echo "Compiling OMP" BUN_COMPILE_EXECUTABLE_PATH="${bunRuntimeTemplate}/libexec/bun" \ bun --cwd="$PWD/packages/coding-agent" run build runHook postBuild ''; installPhase = '' runHook preInstall install -Dm755 packages/coding-agent/dist/omp "$out/bin/omp" # The addon is gzip-compressed inside the compiled binary, so the store # paths it links against are invisible to the output reference scanner. # Record them in plain text to pin the libraries into the runtime closure. mkdir -p "$out/nix-support" ${ if stdenv.hostPlatform.isLinux then '' patchelf --print-rpath "packages/natives/native/${platform.addon}" \ > "$out/nix-support/embedded-addon-runpath" '' else '' echo "${lib.getLib libopus}/lib" > "$out/nix-support/embedded-addon-runpath" '' } runHook postInstall ''; # Bun serializes the build interpreter path into the bundled entrypoint's # inert shebang. Remove its hash before Nix scans output references; this # runs before Darwin's binary-signing fixup hook. preFixup = '' remove-references-to -t ${bun} "$out/bin/omp" ''; disallowedReferences = [ bun ]; doInstallCheck = true; installCheckPhase = '' runHook preInstallCheck HOME="$TMPDIR" "$out/bin/omp" --smoke-test | grep -q "smoke-test: ok" BUN_BE_BUN=1 "$out/bin/omp" -e \ 'if (Bun.version !== "${bun.version}" || typeof Bun.Image !== "function") process.exit(1)' runHook postInstallCheck ''; meta = { description = "Terminal-based coding agent with multi-model support"; homepage = "https://omp.sh"; changelog = "https://github.com/can1357/oh-my-pi/releases/tag/v${packageJson.version}"; license = lib.licenses.mit; mainProgram = "omp"; platforms = [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ]; sourceProvenance = with lib.sourceTypes; [ binaryNativeCode fromSource ]; }; }