From 04556643ff2d6eda99ba68a7523c39735faf02f7 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Wed, 29 Apr 2026 14:17:20 +0800 Subject: [PATCH 01/22] Add Nix flake for Warp Adds a first-party Nix flake that builds the OSS Warp Linux binary from source, installs desktop assets and bundled resources, and exposes a development shell. Co-Authored-By: Warp --- flake.lock | 48 +++++++++ flake.nix | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 349 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..3c9993944 --- /dev/null +++ b/flake.lock @@ -0,0 +1,48 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1777268161, + "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1777432579, + "narHash": "sha256-Ce11TStDsqCge2vAAfLKe2+4lDI5cSX5ZYZOuKJBKKQ=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "3ecb5e6ab380ced3272ef7fcfe398bffbcc0f152", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..95f2a327e --- /dev/null +++ b/flake.nix @@ -0,0 +1,301 @@ +{ + description = "Warp is an agentic development environment, born out of the terminal."; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { + self, + nixpkgs, + rust-overlay, + ... + }: + let + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; + forAllSystems = nixpkgs.lib.genAttrs systems; + in + { + packages = forAllSystems ( + system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ rust-overlay.overlays.default ]; + }; + lib = pkgs.lib; + rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + rustPlatform = pkgs.makeRustPlatform { + cargo = rustToolchain; + rustc = rustToolchain; + }; + + appCargoToml = builtins.fromTOML (builtins.readFile ./app/Cargo.toml); + version = "${appCargoToml.package.version}+${self.shortRev or "dirty"}"; + cargoVendorHash = "sha256-TzYSC82HVRhCxBHLmHw8BIZ4hJKCZfp+s/mfbeAjdQ4="; + warpProtoApis = pkgs.fetchFromGitHub { + owner = "warpdotdev"; + repo = "warp-proto-apis"; + rev = "78a78f21a75432bf0141e396fb318bf1694e47f0"; + hash = "sha256-8bB/tCLIzRCofMK1rYCe8bizUr1U4A6f6uVeckJJKI4="; + }; + warpWorkflows = pkgs.fetchFromGitHub { + owner = "warpdotdev"; + repo = "workflows"; + rev = "793a98ddda6ef19682aed66364faebd2829f0e01"; + hash = "sha256-ICgkxlUUIfyhr0agZEk3KtGHX0uNRlRCKtz0iF2jd7o="; + }; + cargoDeps = pkgs.runCommand "warp-terminal-${version}-vendor" { } '' + cp -R ${ + rustPlatform.fetchCargoVendor { + src = self; + name = "warp-terminal-${version}"; + hash = cargoVendorHash; + } + }/. "$out" + chmod -R u+w "$out" + + # Cargo's vendored git source layout keeps only the selected + # workspace member, while warp_multi_agent_api normally reads the + # sibling .proto files from its full upstream workspace checkout. + # Point the build script at the pinned source tree fetched by Nix. + protoCrate="$(dirname "$(find "$out" -path '*/warp_multi_agent_api-0.0.0/Cargo.toml' -print -quit)")" + if [ -z "$protoCrate" ] || [ "$protoCrate" = "." ]; then + echo "could not find vendored warp_multi_agent_api crate" >&2 + exit 1 + fi + substituteInPlace "$protoCrate/build.rs" \ + --replace-fail \ + 'let proto_path = manifest_dir.parent().unwrap().parent().unwrap();' \ + 'let proto_path = std::path::PathBuf::from("${warpProtoApis}/apis/multi_agent/v1");' + + # The warp-workflows build script similarly expects its sibling + # specs directory from the full workflows workspace checkout. + workflowCrate="$(dirname "$(find "$out" -path '*/warp-workflows-0.1.0/Cargo.toml' -print -quit)")" + if [ -z "$workflowCrate" ] || [ "$workflowCrate" = "." ]; then + echo "could not find vendored warp-workflows crate" >&2 + exit 1 + fi + substituteInPlace "$workflowCrate/build.rs" \ + --replace-fail \ + 'println!("cargo:rerun-if-changed=../specs");' \ + 'println!("cargo:rerun-if-changed=${warpWorkflows}/specs");' \ + --replace-fail \ + 'for entry in WalkDir::new("../specs") {' \ + 'for entry in WalkDir::new("${warpWorkflows}/specs") {' + ''; + + runtimeLibraries = with pkgs; [ + alsa-lib + curl + dbus + expat + fontconfig + freetype + libGL + libgit2 + libxkbcommon + openssl + stdenv.cc.cc.lib + udev + vulkan-loader + wayland + libx11 + libxscrnsaver + libxcursor + libxext + libxfixes + libxi + libxrandr + libxrender + libxcb + zlib + ]; + + warp-terminal = rustPlatform.buildRustPackage { + pname = "warp-terminal"; + inherit version; + + src = self; + inherit cargoDeps; + + nativeBuildInputs = with pkgs; [ + brotli + cargo-about + clang + cmake + jq + makeWrapper + patchelf + pkg-config + protobuf + python3 + ]; + + buildInputs = runtimeLibraries; + + cargoBuildFlags = [ + "-p" + "warp" + "--bin" + "warp-oss" + "--bin" + "generate_settings_schema" + ]; + buildFeatures = [ + "release_bundle" + "gui" + "nld_improvements" + ]; + + # The application test suite is large and GUI/integration-heavy; this + # flake's package check is the Nix build plus a launch smoke test. + doCheck = false; + + env = { + APPIMAGE_NAME = "WarpOss-${pkgs.stdenv.hostPlatform.parsed.cpu.name}.AppImage"; + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; + PROTOC = "${pkgs.protobuf}/bin/protoc"; + PROTOC_INCLUDE = "${pkgs.protobuf}/include"; + CARGO_PROFILE_RELEASE_DEBUG = "false"; + }; + + postInstall = + let + installDir = "$out/opt/warpdotdev/warp-terminal"; + libraryPath = lib.makeLibraryPath runtimeLibraries; + executablePath = lib.makeBinPath (with pkgs; [ xdg-utils ]); + in + '' + install -Dm755 "$out/bin/warp-oss" "${installDir}/warp-oss" + rm -f "$out/bin/warp-oss" + + mkdir -p "${installDir}/resources" + cp -R resources/bundled "${installDir}/resources/bundled" + + "$out/bin/generate_settings_schema" \ + --channel dev \ + "${installDir}/resources/settings_schema.json" + rm -f "$out/bin/generate_settings_schema" + + install -Dm644 LICENSE-AGPL "$out/share/licenses/warp-terminal/LICENSE-AGPL" + install -Dm644 LICENSE-MIT "$out/share/licenses/warp-terminal/LICENSE-MIT" + + install -Dm644 app/channels/oss/dev.warp.WarpOss.desktop \ + "$out/share/applications/dev.warp.WarpOss.desktop" + substituteInPlace "$out/share/applications/dev.warp.WarpOss.desktop" \ + --replace-fail "Exec=warp-oss %U" "Exec=warp-terminal %U" + + for size in 16x16 32x32 64x64 128x128 256x256 512x512; do + icon="app/channels/oss/icon/no-padding/$size.png" + if [ -f "$icon" ]; then + install -Dm644 "$icon" \ + "$out/share/icons/hicolor/$size/apps/dev.warp.WarpOss.png" + fi + done + + wrapProgram "${installDir}/warp-oss" \ + --prefix LD_LIBRARY_PATH : "${libraryPath}" \ + --prefix PATH : "${executablePath}" + + mkdir -p "$out/bin" + ln -s "${installDir}/warp-oss" "$out/bin/warp-oss" + ln -s "${installDir}/warp-oss" "$out/bin/warp-terminal" + ''; + + postFixup = '' + wrapped="/opt/warpdotdev/warp-terminal/.warp-oss-wrapped" + if [ -e "$out$wrapped" ] && ! patchelf --print-needed "$out$wrapped" | grep -q '^libfontconfig\.so\.1$'; then + patchelf --add-needed libfontconfig.so.1 "$out$wrapped" + fi + ''; + + meta = { + description = "Warp is an agentic development environment, born out of the terminal."; + homepage = "https://www.warp.dev"; + license = lib.licenses.agpl3Only; + mainProgram = "warp-terminal"; + platforms = systems; + sourceProvenance = with lib.sourceTypes; [ fromSource ]; + }; + }; + in + { + inherit warp-terminal; + default = warp-terminal; + } + ); + + devShells = forAllSystems ( + system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ rust-overlay.overlays.default ]; + }; + lib = pkgs.lib; + rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + nativeBuildInputs = with pkgs; [ + brotli + cargo-about + cargo-nextest + clang + cmake + jq + lld + pkg-config + protobuf + python3 + rustToolchain + rust-analyzer + ]; + buildInputs = with pkgs; [ + alsa-lib + curl + dbus + expat + fontconfig + freetype + libGL + libgit2 + libxkbcommon + openssl + stdenv.cc.cc.lib + udev + vulkan-loader + wayland + libx11 + libxscrnsaver + libxcursor + libxext + libxfixes + libxi + libxrandr + libxrender + libxcb + zlib + ]; + in + { + default = pkgs.mkShell { + inherit nativeBuildInputs buildInputs; + APPIMAGE_NAME = "WarpOss-${pkgs.stdenv.hostPlatform.parsed.cpu.name}.AppImage"; + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; + PROTOC = "${pkgs.protobuf}/bin/protoc"; + PROTOC_INCLUDE = "${pkgs.protobuf}/include"; + LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs; + }; + } + ); + + formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt); + }; +} From 92d9e282be4a133c561b587a5b0a6508abbb9bec Mon Sep 17 00:00:00 2001 From: VitalyR Date: Wed, 29 Apr 2026 19:12:55 +0800 Subject: [PATCH 02/22] Install third-party license notices in Nix package Use the existing bundled-resource preparation script so the Nix package includes the generated THIRD_PARTY_LICENSES.txt in both bundled resources and share/licenses. --- flake.nix | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 95f2a327e..e6437f585 100644 --- a/flake.nix +++ b/flake.nix @@ -171,6 +171,7 @@ postInstall = let installDir = "$out/opt/warpdotdev/warp-terminal"; + resourcesDir = "${installDir}/resources"; libraryPath = lib.makeLibraryPath runtimeLibraries; executablePath = lib.makeBinPath (with pkgs; [ xdg-utils ]); in @@ -178,14 +179,22 @@ install -Dm755 "$out/bin/warp-oss" "${installDir}/warp-oss" rm -f "$out/bin/warp-oss" - mkdir -p "${installDir}/resources" - cp -R resources/bundled "${installDir}/resources/bundled" + patchShebangs ./script + + SKIP_SETTINGS_SCHEMA=1 ./script/prepare_bundled_resources \ + "${resourcesDir}" \ + dev \ + release "$out/bin/generate_settings_schema" \ --channel dev \ - "${installDir}/resources/settings_schema.json" + "${resourcesDir}/settings_schema.json" rm -f "$out/bin/generate_settings_schema" + install -Dm644 \ + "${resourcesDir}/THIRD_PARTY_LICENSES.txt" \ + "$out/share/licenses/warp-terminal/THIRD_PARTY_LICENSES.txt" + install -Dm644 LICENSE-AGPL "$out/share/licenses/warp-terminal/LICENSE-AGPL" install -Dm644 LICENSE-MIT "$out/share/licenses/warp-terminal/LICENSE-MIT" From 8c58ba5801a0c9bf2b21dc3aeb272eac039129d1 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Wed, 29 Apr 2026 19:35:56 +0800 Subject: [PATCH 03/22] Use stable channel for Nix package resources --- flake.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index e6437f585..351666659 100644 --- a/flake.nix +++ b/flake.nix @@ -172,6 +172,7 @@ let installDir = "$out/opt/warpdotdev/warp-terminal"; resourcesDir = "${installDir}/resources"; + releaseChannel = "stable"; libraryPath = lib.makeLibraryPath runtimeLibraries; executablePath = lib.makeBinPath (with pkgs; [ xdg-utils ]); in @@ -183,11 +184,11 @@ SKIP_SETTINGS_SCHEMA=1 ./script/prepare_bundled_resources \ "${resourcesDir}" \ - dev \ + "${releaseChannel}" \ release "$out/bin/generate_settings_schema" \ - --channel dev \ + --channel "${releaseChannel}" \ "${resourcesDir}/settings_schema.json" rm -f "$out/bin/generate_settings_schema" From b742d4e79ffb2e7a8a5e50d8a1d7512d9bd8d052 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Wed, 29 Apr 2026 20:09:44 +0800 Subject: [PATCH 04/22] Narrow Nix resource script shebang patching --- flake.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 351666659..9d0b784a4 100644 --- a/flake.nix +++ b/flake.nix @@ -180,7 +180,9 @@ install -Dm755 "$out/bin/warp-oss" "${installDir}/warp-oss" rm -f "$out/bin/warp-oss" - patchShebangs ./script + patchShebangs \ + ./script/prepare_bundled_resources \ + ./script/copy_conditional_skills SKIP_SETTINGS_SCHEMA=1 ./script/prepare_bundled_resources \ "${resourcesDir}" \ From 0b3f18b8a929e60c7b669acfd0413addc39d0e26 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 12:58:33 +0800 Subject: [PATCH 05/22] Add macOS flake validation workflow --- .github/workflows/verify-macos-flake-gha.yml | 121 +++++++ flake.nix | 319 ++++++++++++------- 2 files changed, 325 insertions(+), 115 deletions(-) create mode 100644 .github/workflows/verify-macos-flake-gha.yml diff --git a/.github/workflows/verify-macos-flake-gha.yml b/.github/workflows/verify-macos-flake-gha.yml new file mode 100644 index 000000000..2120b6695 --- /dev/null +++ b/.github/workflows/verify-macos-flake-gha.yml @@ -0,0 +1,121 @@ +name: Verify macOS Warp flake + +on: + push: + branches: + - verify-macos-flake-gha + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-launch: + name: Build and launch ${{ matrix.system }} + runs-on: ${{ matrix.runner }} + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + include: + - runner: macos-15 + system: aarch64-darwin + - runner: macos-15-intel + system: x86_64-darwin + + steps: + - name: Checkout sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Show macOS toolchain + run: | + set -euxo pipefail + sw_vers + xcodebuild -version + xcrun --sdk macosx --find metal + xcrun --sdk macosx --find metallib + + - name: Install Nix + uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f # v31.7.0 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Warp macOS app + id: build + run: | + set -euxo pipefail + nix --version + nix config show system + out="$(nix build ".#packages.${{ matrix.system }}.warp-terminal" --print-out-paths -L --accept-flake-config)" + echo "out=$out" >> "$GITHUB_OUTPUT" + + - name: Inspect app bundle + run: | + set -euxo pipefail + out="${{ steps.build.outputs.out }}" + app="$out/Applications/WarpOss.app" + binary="$app/Contents/MacOS/warp-oss" + + test -d "$app" + test -x "$binary" + test -s "$app/Contents/Info.plist" + test -s "$app/Contents/Resources/settings_schema.json" + + file "$binary" + plutil -p "$app/Contents/Info.plist" + otool -L "$binary" | sed -n '1,160p' + + - name: Launch app binary briefly + env: + HOME: ${{ runner.temp }}/warp-home + run: | + set -euxo pipefail + out="${{ steps.build.outputs.out }}" + app="$out/Applications/WarpOss.app" + binary="$app/Contents/MacOS/warp-oss" + stdout="$RUNNER_TEMP/warp-oss.stdout" + stderr="$RUNNER_TEMP/warp-oss.stderr" + log="$HOME/Library/Logs/warp-oss.log" + + mkdir -p "$HOME/Library/Logs" + "$binary" >"$stdout" 2>"$stderr" & + pid="$!" + echo "Started warp-oss with pid $pid" + + runtime_ok=0 + for _ in $(seq 1 20); do + if kill -0 "$pid" 2>/dev/null; then + runtime_ok=1 + if [ -s "$log" ]; then + break + fi + sleep 1 + else + break + fi + done + + if kill -0 "$pid" 2>/dev/null; then + kill "$pid" || true + fi + wait "$pid" || true + + echo "=== warp-oss stdout ===" + sed -n '1,200p' "$stdout" || true + echo "=== warp-oss stderr ===" + sed -n '1,200p' "$stderr" || true + echo "=== warp-oss log ===" + if [ -s "$log" ]; then + tail -n 200 "$log" + else + echo "No warp-oss.log was written." + fi + + if [ "$runtime_ok" -ne 1 ] && [ ! -s "$log" ]; then + echo "warp-oss neither stayed alive briefly nor wrote a log file" >&2 + exit 1 + fi diff --git a/flake.nix b/flake.nix index 9d0b784a4..2e58cac7f 100644 --- a/flake.nix +++ b/flake.nix @@ -20,6 +20,8 @@ systems = [ "x86_64-linux" "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" ]; forAllSystems = nixpkgs.lib.genAttrs systems; in @@ -93,7 +95,7 @@ 'for entry in WalkDir::new("${warpWorkflows}/specs") {' ''; - runtimeLibraries = with pkgs; [ + linuxRuntimeLibraries = with pkgs; [ alsa-lib curl dbus @@ -120,6 +122,20 @@ zlib ]; + darwinBuildInputs = with pkgs; [ + apple-sdk_15 + libiconv + (darwinMinVersionHook "10.14") + ]; + + buildFeatures = [ + "release_bundle" + "gui" + "nld_improvements" + ] ++ lib.optionals pkgs.stdenv.isDarwin [ + "extern_plist" + ]; + warp-terminal = rustPlatform.buildRustPackage { pname = "warp-terminal"; inherit version; @@ -127,20 +143,30 @@ src = self; inherit cargoDeps; - nativeBuildInputs = with pkgs; [ - brotli - cargo-about - clang - cmake - jq - makeWrapper - patchelf - pkg-config - protobuf - python3 - ]; + nativeBuildInputs = + with pkgs; + [ + brotli + cargo-about + clang + cmake + jq + pkg-config + protobuf + python3 + ] + ++ lib.optionals pkgs.stdenv.isLinux [ + makeWrapper + patchelf + ] + ++ lib.optionals pkgs.stdenv.isDarwin [ + cargo-bundle + perl + ]; - buildInputs = runtimeLibraries; + buildInputs = + lib.optionals pkgs.stdenv.isLinux linuxRuntimeLibraries + ++ lib.optionals pkgs.stdenv.isDarwin darwinBuildInputs; cargoBuildFlags = [ "-p" @@ -150,11 +176,7 @@ "--bin" "generate_settings_schema" ]; - buildFeatures = [ - "release_bundle" - "gui" - "nld_improvements" - ]; + inherit buildFeatures; # The application test suite is large and GUI/integration-heavy; this # flake's package check is the Nix build plus a launch smoke test. @@ -166,64 +188,116 @@ PROTOC = "${pkgs.protobuf}/bin/protoc"; PROTOC_INCLUDE = "${pkgs.protobuf}/include"; CARGO_PROFILE_RELEASE_DEBUG = "false"; + } // lib.optionalAttrs pkgs.stdenv.isDarwin { + MACOSX_DEPLOYMENT_TARGET = "10.14"; }; postInstall = - let - installDir = "$out/opt/warpdotdev/warp-terminal"; - resourcesDir = "${installDir}/resources"; - releaseChannel = "stable"; - libraryPath = lib.makeLibraryPath runtimeLibraries; - executablePath = lib.makeBinPath (with pkgs; [ xdg-utils ]); - in - '' - install -Dm755 "$out/bin/warp-oss" "${installDir}/warp-oss" - rm -f "$out/bin/warp-oss" - - patchShebangs \ - ./script/prepare_bundled_resources \ - ./script/copy_conditional_skills - - SKIP_SETTINGS_SCHEMA=1 ./script/prepare_bundled_resources \ - "${resourcesDir}" \ - "${releaseChannel}" \ - release - - "$out/bin/generate_settings_schema" \ - --channel "${releaseChannel}" \ - "${resourcesDir}/settings_schema.json" - rm -f "$out/bin/generate_settings_schema" - - install -Dm644 \ - "${resourcesDir}/THIRD_PARTY_LICENSES.txt" \ - "$out/share/licenses/warp-terminal/THIRD_PARTY_LICENSES.txt" - - install -Dm644 LICENSE-AGPL "$out/share/licenses/warp-terminal/LICENSE-AGPL" - install -Dm644 LICENSE-MIT "$out/share/licenses/warp-terminal/LICENSE-MIT" - - install -Dm644 app/channels/oss/dev.warp.WarpOss.desktop \ - "$out/share/applications/dev.warp.WarpOss.desktop" - substituteInPlace "$out/share/applications/dev.warp.WarpOss.desktop" \ - --replace-fail "Exec=warp-oss %U" "Exec=warp-terminal %U" - - for size in 16x16 32x32 64x64 128x128 256x256 512x512; do - icon="app/channels/oss/icon/no-padding/$size.png" - if [ -f "$icon" ]; then - install -Dm644 "$icon" \ - "$out/share/icons/hicolor/$size/apps/dev.warp.WarpOss.png" - fi - done - - wrapProgram "${installDir}/warp-oss" \ - --prefix LD_LIBRARY_PATH : "${libraryPath}" \ - --prefix PATH : "${executablePath}" - - mkdir -p "$out/bin" - ln -s "${installDir}/warp-oss" "$out/bin/warp-oss" - ln -s "${installDir}/warp-oss" "$out/bin/warp-terminal" - ''; - - postFixup = '' + if pkgs.stdenv.isDarwin then + let + appName = "WarpOss"; + releaseChannel = "oss"; + cargoBundleFeatures = lib.concatStringsSep "," buildFeatures; + appBundle = "target/release/bundle/osx/${appName}.app"; + resourcesDir = "${appBundle}/Contents/Resources"; + in + '' + patchShebangs \ + ./script/prepare_bundled_resources \ + ./script/copy_conditional_skills \ + ./script/compile_icon + + pushd app + CARGO_BUNDLE_SKIP_BUILD=1 cargo bundle \ + --profile release \ + --bin warp-oss \ + --features "${cargoBundleFeatures}" + popd + + export WARP_SCHEME_NAME=warposs + export WARP_PLIST_PATH="${appBundle}/Contents/Info.plist" + ./script/update_plist + + SKIP_SETTINGS_SCHEMA=1 ./script/prepare_bundled_resources \ + "${resourcesDir}" \ + "${releaseChannel}" \ + release + + "$out/bin/generate_settings_schema" \ + --channel "${releaseChannel}" \ + "${resourcesDir}/settings_schema.json" + + ./script/compile_icon "${releaseChannel}" "${appBundle}" + + mkdir -p "$out/Applications" "$out/bin" + mv "${appBundle}" "$out/Applications/${appName}.app" + + rm -f "$out/bin/warp-oss" "$out/bin/generate_settings_schema" + ln -s "$out/Applications/${appName}.app/Contents/MacOS/warp-oss" "$out/bin/warp-oss" + ln -s "$out/Applications/${appName}.app/Contents/MacOS/warp-oss" "$out/bin/warp-terminal" + + install -Dm644 LICENSE-AGPL "$out/share/licenses/warp-terminal/LICENSE-AGPL" + install -Dm644 LICENSE-MIT "$out/share/licenses/warp-terminal/LICENSE-MIT" + install -Dm644 \ + "${resourcesDir}/THIRD_PARTY_LICENSES.txt" \ + "$out/share/licenses/warp-terminal/THIRD_PARTY_LICENSES.txt" + '' + else + let + installDir = "$out/opt/warpdotdev/warp-terminal"; + resourcesDir = "${installDir}/resources"; + releaseChannel = "stable"; + libraryPath = lib.makeLibraryPath linuxRuntimeLibraries; + executablePath = lib.makeBinPath (with pkgs; [ xdg-utils ]); + in + '' + install -Dm755 "$out/bin/warp-oss" "${installDir}/warp-oss" + rm -f "$out/bin/warp-oss" + + patchShebangs \ + ./script/prepare_bundled_resources \ + ./script/copy_conditional_skills + + SKIP_SETTINGS_SCHEMA=1 ./script/prepare_bundled_resources \ + "${resourcesDir}" \ + "${releaseChannel}" \ + release + + "$out/bin/generate_settings_schema" \ + --channel "${releaseChannel}" \ + "${resourcesDir}/settings_schema.json" + rm -f "$out/bin/generate_settings_schema" + + install -Dm644 \ + "${resourcesDir}/THIRD_PARTY_LICENSES.txt" \ + "$out/share/licenses/warp-terminal/THIRD_PARTY_LICENSES.txt" + + install -Dm644 LICENSE-AGPL "$out/share/licenses/warp-terminal/LICENSE-AGPL" + install -Dm644 LICENSE-MIT "$out/share/licenses/warp-terminal/LICENSE-MIT" + + install -Dm644 app/channels/oss/dev.warp.WarpOss.desktop \ + "$out/share/applications/dev.warp.WarpOss.desktop" + substituteInPlace "$out/share/applications/dev.warp.WarpOss.desktop" \ + --replace-fail "Exec=warp-oss %U" "Exec=warp-terminal %U" + + for size in 16x16 32x32 64x64 128x128 256x256 512x512; do + icon="app/channels/oss/icon/no-padding/$size.png" + if [ -f "$icon" ]; then + install -Dm644 "$icon" \ + "$out/share/icons/hicolor/$size/apps/dev.warp.WarpOss.png" + fi + done + + wrapProgram "${installDir}/warp-oss" \ + --prefix LD_LIBRARY_PATH : "${libraryPath}" \ + --prefix PATH : "${executablePath}" + + mkdir -p "$out/bin" + ln -s "${installDir}/warp-oss" "$out/bin/warp-oss" + ln -s "${installDir}/warp-oss" "$out/bin/warp-terminal" + ''; + + postFixup = lib.optionalString pkgs.stdenv.isLinux '' wrapped="/opt/warpdotdev/warp-terminal/.warp-oss-wrapped" if [ -e "$out$wrapped" ] && ! patchelf --print-needed "$out$wrapped" | grep -q '^libfontconfig\.so\.1$'; then patchelf --add-needed libfontconfig.so.1 "$out$wrapped" @@ -255,46 +329,60 @@ }; lib = pkgs.lib; rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - nativeBuildInputs = with pkgs; [ - brotli - cargo-about - cargo-nextest - clang - cmake - jq - lld - pkg-config - protobuf - python3 - rustToolchain - rust-analyzer - ]; - buildInputs = with pkgs; [ - alsa-lib - curl - dbus - expat - fontconfig - freetype - libGL - libgit2 - libxkbcommon - openssl - stdenv.cc.cc.lib - udev - vulkan-loader - wayland - libx11 - libxscrnsaver - libxcursor - libxext - libxfixes - libxi - libxrandr - libxrender - libxcb - zlib - ]; + nativeBuildInputs = + with pkgs; + [ + brotli + cargo-about + cargo-nextest + clang + cmake + jq + lld + pkg-config + protobuf + python3 + rustToolchain + rust-analyzer + ] + ++ lib.optionals pkgs.stdenv.isDarwin [ + cargo-bundle + ]; + buildInputs = + with pkgs; + [ + curl + fontconfig + freetype + libgit2 + openssl + zlib + ] + ++ lib.optionals pkgs.stdenv.isLinux [ + alsa-lib + dbus + expat + libGL + libxkbcommon + stdenv.cc.cc.lib + udev + vulkan-loader + wayland + libx11 + libxscrnsaver + libxcursor + libxext + libxfixes + libxi + libxrandr + libxrender + libxcb + ] + ++ lib.optionals pkgs.stdenv.isDarwin [ + apple-sdk_15 + libiconv + (darwinMinVersionHook "10.14") + ]; in { default = pkgs.mkShell { @@ -303,7 +391,8 @@ LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; PROTOC = "${pkgs.protobuf}/bin/protoc"; PROTOC_INCLUDE = "${pkgs.protobuf}/include"; - LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs; + LD_LIBRARY_PATH = lib.optionalString pkgs.stdenv.isLinux (lib.makeLibraryPath buildInputs); + MACOSX_DEPLOYMENT_TARGET = lib.optionalString pkgs.stdenv.isDarwin "10.14"; }; } ); From 41f729ecd53f48e08a5c4e743d7f0b70bbcd5099 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 13:07:28 +0800 Subject: [PATCH 06/22] Refresh workflows source hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 2e58cac7f..a28a73099 100644 --- a/flake.nix +++ b/flake.nix @@ -53,7 +53,7 @@ owner = "warpdotdev"; repo = "workflows"; rev = "793a98ddda6ef19682aed66364faebd2829f0e01"; - hash = "sha256-ICgkxlUUIfyhr0agZEk3KtGHX0uNRlRCKtz0iF2jd7o="; + hash = "sha256-yRTtgiNpYjpQWHhqGSm9qP7zUtQhuxZfee2ThWRVR/A="; }; cargoDeps = pkgs.runCommand "warp-terminal-${version}-vendor" { } '' cp -R ${ From d37e5a952474957e19cfd47f21e8c7a95ce277b3 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 13:14:04 +0800 Subject: [PATCH 07/22] Refresh cargo vendor hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index a28a73099..f42cd8d7b 100644 --- a/flake.nix +++ b/flake.nix @@ -42,7 +42,7 @@ appCargoToml = builtins.fromTOML (builtins.readFile ./app/Cargo.toml); version = "${appCargoToml.package.version}+${self.shortRev or "dirty"}"; - cargoVendorHash = "sha256-TzYSC82HVRhCxBHLmHw8BIZ4hJKCZfp+s/mfbeAjdQ4="; + cargoVendorHash = "sha256-Pqxzek7hAuj/mlhiaipq+TsufWOsfuabj8T4O70oluw="; warpProtoApis = pkgs.fetchFromGitHub { owner = "warpdotdev"; repo = "warp-proto-apis"; From adb7f15b6d170558ad5295b1e9b35ccb1c6c214d Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 13:43:12 +0800 Subject: [PATCH 08/22] Expose Xcode tools to Darwin build --- .github/workflows/verify-macos-flake-gha.yml | 1 + flake.nix | 27 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.github/workflows/verify-macos-flake-gha.yml b/.github/workflows/verify-macos-flake-gha.yml index 2120b6695..0b6c8823c 100644 --- a/.github/workflows/verify-macos-flake-gha.yml +++ b/.github/workflows/verify-macos-flake-gha.yml @@ -36,6 +36,7 @@ jobs: set -euxo pipefail sw_vers xcodebuild -version + xcode-select -p xcrun --sdk macosx --find metal xcrun --sdk macosx --find metallib diff --git a/flake.nix b/flake.nix index f42cd8d7b..680e73e65 100644 --- a/flake.nix +++ b/flake.nix @@ -9,6 +9,15 @@ }; }; + nixConfig = { + # Warp's macOS build scripts shell out to `xcrun` for `metal` and + # `metallib`, so the Darwin sandbox must see the host Xcode installation. + extra-sandbox-paths = [ + "/Applications?" + "/Library/Developer/CommandLineTools?" + ]; + }; + outputs = { self, @@ -192,6 +201,24 @@ MACOSX_DEPLOYMENT_TARGET = "10.14"; }; + preBuild = lib.optionalString pkgs.stdenv.isDarwin '' + for developerDir in /Applications/Xcode*.app/Contents/Developer /Library/Developer/CommandLineTools; do + if [ -d "$developerDir" ]; then + export DEVELOPER_DIR="$developerDir" + break + fi + done + + if [ -z "''${DEVELOPER_DIR:-}" ]; then + echo "could not locate an Xcode developer directory inside the sandbox" >&2 + exit 1 + fi + + echo "Using DEVELOPER_DIR=$DEVELOPER_DIR" + xcrun --sdk macosx --find metal + xcrun --sdk macosx --find metallib + ''; + postInstall = if pkgs.stdenv.isDarwin then let From 9abbd5eb3124e20b0a5de3ca0818b0f8d6386576 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 14:09:54 +0800 Subject: [PATCH 09/22] Scope Xcode selection to xcrun --- flake.nix | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/flake.nix b/flake.nix index 680e73e65..014ecdd01 100644 --- a/flake.nix +++ b/flake.nix @@ -15,6 +15,10 @@ extra-sandbox-paths = [ "/Applications?" "/Library/Developer/CommandLineTools?" + "/usr/bin/xcode-select?" + "/usr/bin/xcodebuild?" + "/usr/bin/xcrun?" + "/var/db/xcode_select_link?" ]; }; @@ -48,6 +52,32 @@ cargo = rustToolchain; rustc = rustToolchain; }; + xcodeXcrunWrapper = pkgs.writeShellScriptBin "xcrun" '' + set -euo pipefail + + developerDir="''${DEVELOPER_DIR:-}" + if [ -z "$developerDir" ] && [ -x /usr/bin/xcode-select ]; then + selectedDeveloperDir="$(/usr/bin/xcode-select -p 2>/dev/null || true)" + if [ -n "$selectedDeveloperDir" ] && [ -d "$selectedDeveloperDir" ]; then + developerDir="$selectedDeveloperDir" + fi + fi + + if [ -z "$developerDir" ]; then + for candidate in /Applications/Xcode_16.4.app/Contents/Developer /Applications/Xcode.app/Contents/Developer /Applications/Xcode*.app/Contents/Developer /Library/Developer/CommandLineTools; do + if [ -d "$candidate" ]; then + developerDir="$candidate" + break + fi + done + fi + + if [ -n "$developerDir" ]; then + export DEVELOPER_DIR="$developerDir" + fi + + exec /usr/bin/xcrun "$@" + ''; appCargoToml = builtins.fromTOML (builtins.readFile ./app/Cargo.toml); version = "${appCargoToml.package.version}+${self.shortRev or "dirty"}"; @@ -202,19 +232,8 @@ }; preBuild = lib.optionalString pkgs.stdenv.isDarwin '' - for developerDir in /Applications/Xcode*.app/Contents/Developer /Library/Developer/CommandLineTools; do - if [ -d "$developerDir" ]; then - export DEVELOPER_DIR="$developerDir" - break - fi - done - - if [ -z "''${DEVELOPER_DIR:-}" ]; then - echo "could not locate an Xcode developer directory inside the sandbox" >&2 - exit 1 - fi - - echo "Using DEVELOPER_DIR=$DEVELOPER_DIR" + export PATH="${xcodeXcrunWrapper}/bin:$PATH" + echo "Using xcrun wrapper: $(command -v xcrun)" xcrun --sdk macosx --find metal xcrun --sdk macosx --find metallib ''; From a284878915eb466ef0d6b4556912344212f8c179 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 14:22:37 +0800 Subject: [PATCH 10/22] Prefer Xcode 16.4 for xcrun wrapper --- flake.nix | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/flake.nix b/flake.nix index 014ecdd01..22e775de6 100644 --- a/flake.nix +++ b/flake.nix @@ -15,10 +15,8 @@ extra-sandbox-paths = [ "/Applications?" "/Library/Developer/CommandLineTools?" - "/usr/bin/xcode-select?" "/usr/bin/xcodebuild?" "/usr/bin/xcrun?" - "/var/db/xcode_select_link?" ]; }; @@ -56,12 +54,6 @@ set -euo pipefail developerDir="''${DEVELOPER_DIR:-}" - if [ -z "$developerDir" ] && [ -x /usr/bin/xcode-select ]; then - selectedDeveloperDir="$(/usr/bin/xcode-select -p 2>/dev/null || true)" - if [ -n "$selectedDeveloperDir" ] && [ -d "$selectedDeveloperDir" ]; then - developerDir="$selectedDeveloperDir" - fi - fi if [ -z "$developerDir" ]; then for candidate in /Applications/Xcode_16.4.app/Contents/Developer /Applications/Xcode.app/Contents/Developer /Applications/Xcode*.app/Contents/Developer /Library/Developer/CommandLineTools; do @@ -74,6 +66,7 @@ if [ -n "$developerDir" ]; then export DEVELOPER_DIR="$developerDir" + echo "xcrun wrapper using DEVELOPER_DIR=$DEVELOPER_DIR" >&2 fi exec /usr/bin/xcrun "$@" From a35511421de1a143fe9ab46c100bd29237eb534b Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 14:36:41 +0800 Subject: [PATCH 11/22] Ignore Nix SDK DEVELOPER_DIR for Xcode tools --- flake.nix | 58 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/flake.nix b/flake.nix index 22e775de6..bce7f52cc 100644 --- a/flake.nix +++ b/flake.nix @@ -50,23 +50,59 @@ cargo = rustToolchain; rustc = rustToolchain; }; - xcodeXcrunWrapper = pkgs.writeShellScriptBin "xcrun" '' + hostXcodeSelection = '' + select_host_xcode_developer_dir() { + local developerDir="" + + case "''${DEVELOPER_DIR:-}" in + /nix/store/*) ;; + *) + if [ -n "''${DEVELOPER_DIR:-}" ] && [ -d "''${DEVELOPER_DIR:-}" ]; then + developerDir="''${DEVELOPER_DIR:-}" + fi + ;; + esac + + if [ -z "$developerDir" ]; then + for candidate in /Applications/Xcode_16.4.app/Contents/Developer /Applications/Xcode.app/Contents/Developer /Applications/Xcode*.app/Contents/Developer /Library/Developer/CommandLineTools; do + if [ -d "$candidate" ]; then + developerDir="$candidate" + break + fi + done + fi + + printf '%s' "$developerDir" + } + ''; + xcodeSelectWrapper = pkgs.writeShellScriptBin "xcode-select" '' set -euo pipefail - developerDir="''${DEVELOPER_DIR:-}" + ${hostXcodeSelection} - if [ -z "$developerDir" ]; then - for candidate in /Applications/Xcode_16.4.app/Contents/Developer /Applications/Xcode.app/Contents/Developer /Applications/Xcode*.app/Contents/Developer /Library/Developer/CommandLineTools; do - if [ -d "$candidate" ]; then - developerDir="$candidate" - break - fi - done + if [ "''${1:-}" = "-p" ] || [ "''${1:-}" = "--print-path" ]; then + developerDir="$(select_host_xcode_developer_dir)" + if [ -n "$developerDir" ]; then + printf '%s\n' "$developerDir" + exit 0 + fi fi + unset DEVELOPER_DIR + exec /usr/bin/xcode-select "$@" + ''; + xcodeXcrunWrapper = pkgs.writeShellScriptBin "xcrun" '' + set -euo pipefail + + ${hostXcodeSelection} + + developerDir="$(select_host_xcode_developer_dir)" if [ -n "$developerDir" ]; then export DEVELOPER_DIR="$developerDir" echo "xcrun wrapper using DEVELOPER_DIR=$DEVELOPER_DIR" >&2 + else + unset DEVELOPER_DIR + echo "xcrun wrapper could not locate a host Xcode developer dir; falling back to system xcrun" >&2 fi exec /usr/bin/xcrun "$@" @@ -225,7 +261,9 @@ }; preBuild = lib.optionalString pkgs.stdenv.isDarwin '' - export PATH="${xcodeXcrunWrapper}/bin:$PATH" + export PATH="${xcodeSelectWrapper}/bin:${xcodeXcrunWrapper}/bin:$PATH" + echo "Using xcode-select wrapper: $(command -v xcode-select)" + xcode-select -p echo "Using xcrun wrapper: $(command -v xcrun)" xcrun --sdk macosx --find metal xcrun --sdk macosx --find metallib From d4d8e5a3f0af5e4d1d4e4d60467d6ac10fd2a052 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 15:28:36 +0800 Subject: [PATCH 12/22] Fix Darwin bundle target path --- flake.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index bce7f52cc..43c0c8235 100644 --- a/flake.nix +++ b/flake.nix @@ -274,8 +274,9 @@ let appName = "WarpOss"; releaseChannel = "oss"; + cargoTarget = pkgs.stdenv.hostPlatform.rust.rustcTarget; cargoBundleFeatures = lib.concatStringsSep "," buildFeatures; - appBundle = "target/release/bundle/osx/${appName}.app"; + appBundle = "target/${cargoTarget}/release/bundle/osx/${appName}.app"; resourcesDir = "${appBundle}/Contents/Resources"; in '' @@ -287,6 +288,7 @@ pushd app CARGO_BUNDLE_SKIP_BUILD=1 cargo bundle \ --profile release \ + --target "${cargoTarget}" \ --bin warp-oss \ --features "${cargoBundleFeatures}" popd From 508d2137d83e81928e7f08ff3cbbf9cac06a6c16 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 16:15:19 +0800 Subject: [PATCH 13/22] Expose plutil for Darwin bundle metadata --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 43c0c8235..b69674362 100644 --- a/flake.nix +++ b/flake.nix @@ -15,6 +15,7 @@ extra-sandbox-paths = [ "/Applications?" "/Library/Developer/CommandLineTools?" + "/usr/bin/plutil?" "/usr/bin/xcodebuild?" "/usr/bin/xcrun?" ]; From 4f50bc8331ec41f954c0c64e322a4049a626631d Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 17:04:28 +0800 Subject: [PATCH 14/22] Wrap Darwin plist and Xcode tools --- flake.nix | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index b69674362..00d89bcee 100644 --- a/flake.nix +++ b/flake.nix @@ -10,8 +10,8 @@ }; nixConfig = { - # Warp's macOS build scripts shell out to `xcrun` for `metal` and - # `metallib`, so the Darwin sandbox must see the host Xcode installation. + # Warp's macOS build scripts shell out to host Xcode tools for Metal and + # bundle metadata, so the Darwin sandbox must see the host tool stubs. extra-sandbox-paths = [ "/Applications?" "/Library/Developer/CommandLineTools?" @@ -76,6 +76,25 @@ printf '%s' "$developerDir" } ''; + hostPlutilWrapper = pkgs.writeShellScriptBin "plutil" '' + set -euo pipefail + + exec /usr/bin/plutil "$@" + ''; + xcodeBuildWrapper = pkgs.writeShellScriptBin "xcodebuild" '' + set -euo pipefail + + ${hostXcodeSelection} + + developerDir="$(select_host_xcode_developer_dir)" + if [ -n "$developerDir" ]; then + export DEVELOPER_DIR="$developerDir" + else + unset DEVELOPER_DIR + fi + + exec /usr/bin/xcodebuild "$@" + ''; xcodeSelectWrapper = pkgs.writeShellScriptBin "xcode-select" '' set -euo pipefail @@ -230,7 +249,11 @@ ] ++ lib.optionals pkgs.stdenv.isDarwin [ cargo-bundle + hostPlutilWrapper perl + xcodeBuildWrapper + xcodeSelectWrapper + xcodeXcrunWrapper ]; buildInputs = @@ -262,7 +285,9 @@ }; preBuild = lib.optionalString pkgs.stdenv.isDarwin '' - export PATH="${xcodeSelectWrapper}/bin:${xcodeXcrunWrapper}/bin:$PATH" + export PATH="${hostPlutilWrapper}/bin:${xcodeBuildWrapper}/bin:${xcodeSelectWrapper}/bin:${xcodeXcrunWrapper}/bin:$PATH" + echo "Using plutil wrapper: $(command -v plutil)" + echo "Using xcodebuild wrapper: $(command -v xcodebuild)" echo "Using xcode-select wrapper: $(command -v xcode-select)" xcode-select -p echo "Using xcrun wrapper: $(command -v xcrun)" From be3616b13cc3d3e2224665ddbd04a30d94067584 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 18:10:17 +0800 Subject: [PATCH 15/22] Fix Darwin bundle license install path --- flake.nix | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/flake.nix b/flake.nix index 00d89bcee..ed81833db 100644 --- a/flake.nix +++ b/flake.nix @@ -304,6 +304,8 @@ cargoBundleFeatures = lib.concatStringsSep "," buildFeatures; appBundle = "target/${cargoTarget}/release/bundle/osx/${appName}.app"; resourcesDir = "${appBundle}/Contents/Resources"; + installedAppBundle = "$out/Applications/${appName}.app"; + installedResourcesDir = "${installedAppBundle}/Contents/Resources"; in '' patchShebangs \ @@ -335,16 +337,16 @@ ./script/compile_icon "${releaseChannel}" "${appBundle}" mkdir -p "$out/Applications" "$out/bin" - mv "${appBundle}" "$out/Applications/${appName}.app" + mv "${appBundle}" "${installedAppBundle}" rm -f "$out/bin/warp-oss" "$out/bin/generate_settings_schema" - ln -s "$out/Applications/${appName}.app/Contents/MacOS/warp-oss" "$out/bin/warp-oss" - ln -s "$out/Applications/${appName}.app/Contents/MacOS/warp-oss" "$out/bin/warp-terminal" + ln -s "${installedAppBundle}/Contents/MacOS/warp-oss" "$out/bin/warp-oss" + ln -s "${installedAppBundle}/Contents/MacOS/warp-oss" "$out/bin/warp-terminal" install -Dm644 LICENSE-AGPL "$out/share/licenses/warp-terminal/LICENSE-AGPL" install -Dm644 LICENSE-MIT "$out/share/licenses/warp-terminal/LICENSE-MIT" install -Dm644 \ - "${resourcesDir}/THIRD_PARTY_LICENSES.txt" \ + "${installedResourcesDir}/THIRD_PARTY_LICENSES.txt" \ "$out/share/licenses/warp-terminal/THIRD_PARTY_LICENSES.txt" '' else From 298d7ebfc74e40ae1fd9b4c14aeb3009d3e37f54 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 19:14:04 +0800 Subject: [PATCH 16/22] Upload verified macOS DMG artifacts --- .github/workflows/verify-macos-flake-gha.yml | 94 ++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/.github/workflows/verify-macos-flake-gha.yml b/.github/workflows/verify-macos-flake-gha.yml index 0b6c8823c..2016e5ca3 100644 --- a/.github/workflows/verify-macos-flake-gha.yml +++ b/.github/workflows/verify-macos-flake-gha.yml @@ -120,3 +120,97 @@ jobs: echo "warp-oss neither stayed alive briefly nor wrote a log file" >&2 exit 1 fi + + - name: Package DMG + id: package + run: | + set -euxo pipefail + out="${{ steps.build.outputs.out }}" + app="$out/Applications/WarpOss.app" + dmg_dir="$RUNNER_TEMP/warp-dmg" + staging="$RUNNER_TEMP/warp-dmg-staging" + dmg="$dmg_dir/WarpOss-${{ matrix.system }}.dmg" + + rm -rf "$dmg_dir" "$staging" + mkdir -p "$dmg_dir" + mkdir -p "$staging" + ditto "$app" "$staging/WarpOss.app" + ln -s /Applications "$staging/Applications" + + hdiutil create \ + -volname "WarpOss ${{ matrix.system }}" \ + -srcfolder "$staging" \ + -ov \ + -format UDZO \ + "$dmg" + ls -lh "$dmg" + echo "dmg=$dmg" >> "$GITHUB_OUTPUT" + + - name: Validate DMG contents and launch + env: + HOME: ${{ runner.temp }}/warp-dmg-home + run: | + set -euxo pipefail + dmg="${{ steps.package.outputs.dmg }}" + mount="$RUNNER_TEMP/warp-dmg-mount" + stdout="$RUNNER_TEMP/warp-oss-dmg.stdout" + stderr="$RUNNER_TEMP/warp-oss-dmg.stderr" + log="$HOME/Library/Logs/warp-oss.log" + + rm -rf "$mount" + mkdir -p "$mount" + mkdir -p "$HOME/Library/Logs" + hdiutil attach -nobrowse -readonly -mountpoint "$mount" "$dmg" + trap 'hdiutil detach "$mount" || true' EXIT + + app="$mount/WarpOss.app" + binary="$app/Contents/MacOS/warp-oss" + test -d "$app" + test -x "$binary" + test -s "$app/Contents/Info.plist" + test -s "$app/Contents/Resources/settings_schema.json" + + "$binary" >"$stdout" 2>"$stderr" & + pid="$!" + echo "Started DMG warp-oss with pid $pid" + + runtime_ok=0 + for _ in $(seq 1 20); do + if kill -0 "$pid" 2>/dev/null; then + runtime_ok=1 + if [ -s "$log" ]; then + break + fi + sleep 1 + else + break + fi + done + + if kill -0 "$pid" 2>/dev/null; then + kill "$pid" || true + fi + wait "$pid" || true + + echo "=== DMG warp-oss stdout ===" + sed -n '1,200p' "$stdout" || true + echo "=== DMG warp-oss stderr ===" + sed -n '1,200p' "$stderr" || true + echo "=== DMG warp-oss log ===" + if [ -s "$log" ]; then + tail -n 200 "$log" + else + echo "No warp-oss.log was written." + fi + + if [ "$runtime_ok" -ne 1 ] && [ ! -s "$log" ]; then + echo "DMG warp-oss neither stayed alive briefly nor wrote a log file" >&2 + exit 1 + fi + + - name: Upload DMG artifact + uses: actions/upload-artifact@v4 + with: + name: warp-oss-dmg-${{ matrix.system }} + path: ${{ steps.package.outputs.dmg }} + if-no-files-found: error From 309c3196e3d9b262547f37a1ae689ab17655aeb4 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 20:19:59 +0800 Subject: [PATCH 17/22] Simplify macOS verification smoke steps --- .github/scripts/smoke-warp-macos-app.sh | 54 ++++++++++ .github/workflows/verify-macos-flake-gha.yml | 103 ++----------------- 2 files changed, 61 insertions(+), 96 deletions(-) create mode 100644 .github/scripts/smoke-warp-macos-app.sh diff --git a/.github/scripts/smoke-warp-macos-app.sh b/.github/scripts/smoke-warp-macos-app.sh new file mode 100644 index 000000000..3b29ff054 --- /dev/null +++ b/.github/scripts/smoke-warp-macos-app.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -euxo pipefail + +app="${1:?usage: smoke-warp-macos-app.sh [label]}" +label="${2:-warp-oss}" +slug="$(printf '%s' "$label" | tr -c '[:alnum:]._-' '-')" +binary="$app/Contents/MacOS/warp-oss" +stdout="${RUNNER_TEMP:?}/${slug}.stdout" +stderr="${RUNNER_TEMP:?}/${slug}.stderr" +log="${HOME:?}/Library/Logs/warp-oss.log" + +test -d "$app" +test -x "$binary" +test -s "$app/Contents/Info.plist" +test -s "$app/Contents/Resources/settings_schema.json" + +mkdir -p "$HOME/Library/Logs" +"$binary" >"$stdout" 2>"$stderr" & +pid="$!" +echo "Started $label with pid $pid" + +runtime_ok=0 +for _ in $(seq 1 20); do + if ! kill -0 "$pid" 2>/dev/null; then + break + fi + + runtime_ok=1 + if [ -s "$log" ]; then + break + fi + sleep 1 +done + +if kill -0 "$pid" 2>/dev/null; then + kill "$pid" || true +fi +wait "$pid" || true + +echo "=== $label stdout ===" +sed -n '1,200p' "$stdout" || true +echo "=== $label stderr ===" +sed -n '1,200p' "$stderr" || true +echo "=== $label log ===" +if [ -s "$log" ]; then + tail -n 200 "$log" +else + echo "No warp-oss.log was written." +fi + +if [ "$runtime_ok" -ne 1 ] && [ ! -s "$log" ]; then + echo "$label neither stayed alive briefly nor wrote a log file" >&2 + exit 1 +fi diff --git a/.github/workflows/verify-macos-flake-gha.yml b/.github/workflows/verify-macos-flake-gha.yml index 2016e5ca3..390236c46 100644 --- a/.github/workflows/verify-macos-flake-gha.yml +++ b/.github/workflows/verify-macos-flake-gha.yml @@ -74,52 +74,9 @@ jobs: env: HOME: ${{ runner.temp }}/warp-home run: | - set -euxo pipefail - out="${{ steps.build.outputs.out }}" - app="$out/Applications/WarpOss.app" - binary="$app/Contents/MacOS/warp-oss" - stdout="$RUNNER_TEMP/warp-oss.stdout" - stderr="$RUNNER_TEMP/warp-oss.stderr" - log="$HOME/Library/Logs/warp-oss.log" - - mkdir -p "$HOME/Library/Logs" - "$binary" >"$stdout" 2>"$stderr" & - pid="$!" - echo "Started warp-oss with pid $pid" - - runtime_ok=0 - for _ in $(seq 1 20); do - if kill -0 "$pid" 2>/dev/null; then - runtime_ok=1 - if [ -s "$log" ]; then - break - fi - sleep 1 - else - break - fi - done - - if kill -0 "$pid" 2>/dev/null; then - kill "$pid" || true - fi - wait "$pid" || true - - echo "=== warp-oss stdout ===" - sed -n '1,200p' "$stdout" || true - echo "=== warp-oss stderr ===" - sed -n '1,200p' "$stderr" || true - echo "=== warp-oss log ===" - if [ -s "$log" ]; then - tail -n 200 "$log" - else - echo "No warp-oss.log was written." - fi - - if [ "$runtime_ok" -ne 1 ] && [ ! -s "$log" ]; then - echo "warp-oss neither stayed alive briefly nor wrote a log file" >&2 - exit 1 - fi + bash .github/scripts/smoke-warp-macos-app.sh \ + "${{ steps.build.outputs.out }}/Applications/WarpOss.app" \ + "warp-oss" - name: Package DMG id: package @@ -132,8 +89,7 @@ jobs: dmg="$dmg_dir/WarpOss-${{ matrix.system }}.dmg" rm -rf "$dmg_dir" "$staging" - mkdir -p "$dmg_dir" - mkdir -p "$staging" + mkdir -p "$dmg_dir" "$staging" ditto "$app" "$staging/WarpOss.app" ln -s /Applications "$staging/Applications" @@ -153,60 +109,15 @@ jobs: set -euxo pipefail dmg="${{ steps.package.outputs.dmg }}" mount="$RUNNER_TEMP/warp-dmg-mount" - stdout="$RUNNER_TEMP/warp-oss-dmg.stdout" - stderr="$RUNNER_TEMP/warp-oss-dmg.stderr" - log="$HOME/Library/Logs/warp-oss.log" rm -rf "$mount" mkdir -p "$mount" - mkdir -p "$HOME/Library/Logs" hdiutil attach -nobrowse -readonly -mountpoint "$mount" "$dmg" trap 'hdiutil detach "$mount" || true' EXIT - app="$mount/WarpOss.app" - binary="$app/Contents/MacOS/warp-oss" - test -d "$app" - test -x "$binary" - test -s "$app/Contents/Info.plist" - test -s "$app/Contents/Resources/settings_schema.json" - - "$binary" >"$stdout" 2>"$stderr" & - pid="$!" - echo "Started DMG warp-oss with pid $pid" - - runtime_ok=0 - for _ in $(seq 1 20); do - if kill -0 "$pid" 2>/dev/null; then - runtime_ok=1 - if [ -s "$log" ]; then - break - fi - sleep 1 - else - break - fi - done - - if kill -0 "$pid" 2>/dev/null; then - kill "$pid" || true - fi - wait "$pid" || true - - echo "=== DMG warp-oss stdout ===" - sed -n '1,200p' "$stdout" || true - echo "=== DMG warp-oss stderr ===" - sed -n '1,200p' "$stderr" || true - echo "=== DMG warp-oss log ===" - if [ -s "$log" ]; then - tail -n 200 "$log" - else - echo "No warp-oss.log was written." - fi - - if [ "$runtime_ok" -ne 1 ] && [ ! -s "$log" ]; then - echo "DMG warp-oss neither stayed alive briefly nor wrote a log file" >&2 - exit 1 - fi + bash .github/scripts/smoke-warp-macos-app.sh \ + "$mount/WarpOss.app" \ + "DMG warp-oss" - name: Upload DMG artifact uses: actions/upload-artifact@v4 From 0279d218871abec4dd2aa1e00c6a7605382dde26 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 22:58:12 +0800 Subject: [PATCH 18/22] Refresh workflows source hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index ed81833db..a06f13d3c 100644 --- a/flake.nix +++ b/flake.nix @@ -141,7 +141,7 @@ owner = "warpdotdev"; repo = "workflows"; rev = "793a98ddda6ef19682aed66364faebd2829f0e01"; - hash = "sha256-yRTtgiNpYjpQWHhqGSm9qP7zUtQhuxZfee2ThWRVR/A="; + hash = "sha256-ICgkxlUUIfyhr0agZEk3KtGHX0uNRlRCKtz0iF2jd7o="; }; cargoDeps = pkgs.runCommand "warp-terminal-${version}-vendor" { } '' cp -R ${ From 2a4011070651ad639c4206db306833cf9a8cb310 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Fri, 1 May 2026 23:04:55 +0800 Subject: [PATCH 19/22] Refresh cargo vendor hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index a06f13d3c..7d21890b1 100644 --- a/flake.nix +++ b/flake.nix @@ -130,7 +130,7 @@ appCargoToml = builtins.fromTOML (builtins.readFile ./app/Cargo.toml); version = "${appCargoToml.package.version}+${self.shortRev or "dirty"}"; - cargoVendorHash = "sha256-Pqxzek7hAuj/mlhiaipq+TsufWOsfuabj8T4O70oluw="; + cargoVendorHash = "sha256-TzYSC82HVRhCxBHLmHw8BIZ4hJKCZfp+s/mfbeAjdQ4="; warpProtoApis = pkgs.fetchFromGitHub { owner = "warpdotdev"; repo = "warp-proto-apis"; From 0c2ea3517de39e3f4c2060d8509c63f9c0bddbf4 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Sat, 2 May 2026 14:52:21 +0800 Subject: [PATCH 20/22] Simplify Darwin Xcode wrapper setup --- flake.nix | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/flake.nix b/flake.nix index 7d21890b1..eee394cad 100644 --- a/flake.nix +++ b/flake.nix @@ -75,6 +75,16 @@ printf '%s' "$developerDir" } + + configure_host_xcode_developer_dir() { + local developerDir + developerDir="$(select_host_xcode_developer_dir)" + if [ -n "$developerDir" ]; then + export DEVELOPER_DIR="$developerDir" + else + unset DEVELOPER_DIR + fi + } ''; hostPlutilWrapper = pkgs.writeShellScriptBin "plutil" '' set -euo pipefail @@ -86,13 +96,7 @@ ${hostXcodeSelection} - developerDir="$(select_host_xcode_developer_dir)" - if [ -n "$developerDir" ]; then - export DEVELOPER_DIR="$developerDir" - else - unset DEVELOPER_DIR - fi - + configure_host_xcode_developer_dir exec /usr/bin/xcodebuild "$@" ''; xcodeSelectWrapper = pkgs.writeShellScriptBin "xcode-select" '' @@ -116,12 +120,10 @@ ${hostXcodeSelection} - developerDir="$(select_host_xcode_developer_dir)" - if [ -n "$developerDir" ]; then - export DEVELOPER_DIR="$developerDir" + configure_host_xcode_developer_dir + if [ -n "''${DEVELOPER_DIR:-}" ]; then echo "xcrun wrapper using DEVELOPER_DIR=$DEVELOPER_DIR" >&2 else - unset DEVELOPER_DIR echo "xcrun wrapper could not locate a host Xcode developer dir; falling back to system xcrun" >&2 fi From 6bc1f04e0dbd6e1f566d6cfc7226a162f18bee25 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Sat, 2 May 2026 15:12:12 +0800 Subject: [PATCH 21/22] Simplify smoke and Xcode helpers --- .github/scripts/smoke-warp-macos-app.sh | 20 +++++++++++++------- flake.nix | 14 +++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/scripts/smoke-warp-macos-app.sh b/.github/scripts/smoke-warp-macos-app.sh index 3b29ff054..c87297612 100644 --- a/.github/scripts/smoke-warp-macos-app.sh +++ b/.github/scripts/smoke-warp-macos-app.sh @@ -9,6 +9,14 @@ stdout="${RUNNER_TEMP:?}/${slug}.stdout" stderr="${RUNNER_TEMP:?}/${slug}.stderr" log="${HOME:?}/Library/Logs/warp-oss.log" +dump_stream() { + local title="$1" + local path="$2" + + echo "=== $title ===" + sed -n '1,200p' "$path" || true +} + test -d "$app" test -x "$binary" test -s "$app/Contents/Info.plist" @@ -19,13 +27,13 @@ mkdir -p "$HOME/Library/Logs" pid="$!" echo "Started $label with pid $pid" -runtime_ok=0 +runtime_seen=0 for _ in $(seq 1 20); do if ! kill -0 "$pid" 2>/dev/null; then break fi - runtime_ok=1 + runtime_seen=1 if [ -s "$log" ]; then break fi @@ -37,10 +45,8 @@ if kill -0 "$pid" 2>/dev/null; then fi wait "$pid" || true -echo "=== $label stdout ===" -sed -n '1,200p' "$stdout" || true -echo "=== $label stderr ===" -sed -n '1,200p' "$stderr" || true +dump_stream "$label stdout" "$stdout" +dump_stream "$label stderr" "$stderr" echo "=== $label log ===" if [ -s "$log" ]; then tail -n 200 "$log" @@ -48,7 +54,7 @@ else echo "No warp-oss.log was written." fi -if [ "$runtime_ok" -ne 1 ] && [ ! -s "$log" ]; then +if [ "$runtime_seen" -ne 1 ] && [ ! -s "$log" ]; then echo "$label neither stayed alive briefly nor wrote a log file" >&2 exit 1 fi diff --git a/flake.nix b/flake.nix index eee394cad..dd6236d45 100644 --- a/flake.nix +++ b/flake.nix @@ -51,7 +51,7 @@ cargo = rustToolchain; rustc = rustToolchain; }; - hostXcodeSelection = '' + hostXcodeHelpers = '' select_host_xcode_developer_dir() { local developerDir="" @@ -94,7 +94,7 @@ xcodeBuildWrapper = pkgs.writeShellScriptBin "xcodebuild" '' set -euo pipefail - ${hostXcodeSelection} + ${hostXcodeHelpers} configure_host_xcode_developer_dir exec /usr/bin/xcodebuild "$@" @@ -102,12 +102,12 @@ xcodeSelectWrapper = pkgs.writeShellScriptBin "xcode-select" '' set -euo pipefail - ${hostXcodeSelection} + ${hostXcodeHelpers} if [ "''${1:-}" = "-p" ] || [ "''${1:-}" = "--print-path" ]; then - developerDir="$(select_host_xcode_developer_dir)" - if [ -n "$developerDir" ]; then - printf '%s\n' "$developerDir" + configure_host_xcode_developer_dir + if [ -n "''${DEVELOPER_DIR:-}" ]; then + printf '%s\n' "$DEVELOPER_DIR" exit 0 fi fi @@ -118,7 +118,7 @@ xcodeXcrunWrapper = pkgs.writeShellScriptBin "xcrun" '' set -euo pipefail - ${hostXcodeSelection} + ${hostXcodeHelpers} configure_host_xcode_developer_dir if [ -n "''${DEVELOPER_DIR:-}" ]; then From 19b64f48e7f3dc130cbfa581de90ce8605fcad19 Mon Sep 17 00:00:00 2001 From: VitalyR Date: Sat, 2 May 2026 17:36:17 +0800 Subject: [PATCH 22/22] Move auxiliary source pins to flake inputs --- flake.lock | 36 +++++++++++++++++++++++++++++++++++- flake.nix | 28 ++++++++++++++-------------- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 3c9993944..0a9baf3be 100644 --- a/flake.lock +++ b/flake.lock @@ -19,7 +19,9 @@ "root": { "inputs": { "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" + "rust-overlay": "rust-overlay", + "warpProtoApis": "warpProtoApis", + "warpWorkflows": "warpWorkflows" } }, "rust-overlay": { @@ -41,6 +43,38 @@ "repo": "rust-overlay", "type": "github" } + }, + "warpProtoApis": { + "flake": false, + "locked": { + "lastModified": 1776900698, + "narHash": "sha256-8bB/tCLIzRCofMK1rYCe8bizUr1U4A6f6uVeckJJKI4=", + "owner": "warpdotdev", + "repo": "warp-proto-apis", + "rev": "78a78f21a75432bf0141e396fb318bf1694e47f0", + "type": "github" + }, + "original": { + "owner": "warpdotdev", + "repo": "warp-proto-apis", + "type": "github" + } + }, + "warpWorkflows": { + "flake": false, + "locked": { + "lastModified": 1776965078, + "narHash": "sha256-ICgkxlUUIfyhr0agZEk3KtGHX0uNRlRCKtz0iF2jd7o=", + "owner": "warpdotdev", + "repo": "workflows", + "rev": "793a98ddda6ef19682aed66364faebd2829f0e01", + "type": "github" + }, + "original": { + "owner": "warpdotdev", + "repo": "workflows", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index dd6236d45..adec4ac8a 100644 --- a/flake.nix +++ b/flake.nix @@ -7,6 +7,14 @@ url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; + warpProtoApis = { + url = "github:warpdotdev/warp-proto-apis"; + flake = false; + }; + warpWorkflows = { + url = "github:warpdotdev/workflows"; + flake = false; + }; }; nixConfig = { @@ -26,6 +34,8 @@ self, nixpkgs, rust-overlay, + warpProtoApis, + warpWorkflows, ... }: let @@ -133,18 +143,6 @@ appCargoToml = builtins.fromTOML (builtins.readFile ./app/Cargo.toml); version = "${appCargoToml.package.version}+${self.shortRev or "dirty"}"; cargoVendorHash = "sha256-TzYSC82HVRhCxBHLmHw8BIZ4hJKCZfp+s/mfbeAjdQ4="; - warpProtoApis = pkgs.fetchFromGitHub { - owner = "warpdotdev"; - repo = "warp-proto-apis"; - rev = "78a78f21a75432bf0141e396fb318bf1694e47f0"; - hash = "sha256-8bB/tCLIzRCofMK1rYCe8bizUr1U4A6f6uVeckJJKI4="; - }; - warpWorkflows = pkgs.fetchFromGitHub { - owner = "warpdotdev"; - repo = "workflows"; - rev = "793a98ddda6ef19682aed66364faebd2829f0e01"; - hash = "sha256-ICgkxlUUIfyhr0agZEk3KtGHX0uNRlRCKtz0iF2jd7o="; - }; cargoDeps = pkgs.runCommand "warp-terminal-${version}-vendor" { } '' cp -R ${ rustPlatform.fetchCargoVendor { @@ -222,7 +220,8 @@ "release_bundle" "gui" "nld_improvements" - ] ++ lib.optionals pkgs.stdenv.isDarwin [ + ] + ++ lib.optionals pkgs.stdenv.isDarwin [ "extern_plist" ]; @@ -282,7 +281,8 @@ PROTOC = "${pkgs.protobuf}/bin/protoc"; PROTOC_INCLUDE = "${pkgs.protobuf}/include"; CARGO_PROFILE_RELEASE_DEBUG = "false"; - } // lib.optionalAttrs pkgs.stdenv.isDarwin { + } + // lib.optionalAttrs pkgs.stdenv.isDarwin { MACOSX_DEPLOYMENT_TARGET = "10.14"; };