{ lib, stdenv, fetchFromGitHub, rustPlatform, pkg-config, cargo-tauri, bun, nodejs, pnpm_10, fetchPnpmDeps, pnpmConfigHook, cargo, rustc, wrapGAppsHook3, makeWrapper, dbus, glib, gtk3, libsoup_3, librsvg, libayatana-appindicator, glib-networking, openssl, webkitgtk_4_1, gst_all_1, inputs ? null, }: let # Reuse the anomalyco/opencode binary already pinned in the flake opencode = inputs.opencode.packages.${stdenv.hostPlatform.system}.default; # NOTE: bun build --compile is run WITHOUT --target inside the Nix sandbox. # Specifying a cross-target would cause Bun to download a remote runtime, # which is forbidden in sandbox mode. We build for the host and rename the # output binary to the Rust target triple that Tauri expects. in rustPlatform.buildRustPackage (finalAttrs: { pname = "openwork"; version = "0.11.199"; src = fetchFromGitHub { owner = "different-ai"; repo = "openwork"; rev = "v${finalAttrs.version}"; hash = "sha256-ErON7clClL0iFFbko4cAKgZROt/bJ8k9FTX8eivrDnA="; }; # Rust crate lives inside the monorepo under apps/desktop/src-tauri cargoRoot = "apps/desktop/src-tauri"; cargoLock.lockFile = finalAttrs.src + "/apps/desktop/src-tauri/Cargo.lock"; buildAndTestSubdir = finalAttrs.cargoRoot; # Prefetch the entire pnpm workspace store as a fixed-output derivation. # After the first successful build, replace lib.fakeHash with the real hash # from the error output. pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; pnpm = pnpm_10; fetcherVersion = 2; hash = "sha256-+fN9h9htN5nGsh4wG4DqCilykmnJn0DDoFtrlF/ajRU="; }; nativeBuildInputs = [ pkg-config cargo-tauri.hook bun nodejs # needed for patchShebangs pnpm_10 pnpmConfigHook # installs workspace node_modules offline from pnpmDeps cargo rustc makeWrapper ] ++ lib.optionals stdenv.hostPlatform.isLinux [wrapGAppsHook3]; buildInputs = lib.optionals stdenv.hostPlatform.isLinux [ dbus glib gtk3 libsoup_3 librsvg libayatana-appindicator glib-networking openssl webkitgtk_4_1 gst_all_1.gstreamer gst_all_1.gst-plugins-base gst_all_1.gst-plugins-good gst_all_1.gst-plugins-bad ]; strictDeps = true; # These two tests require docker or rely on OS-level process/timeout # behaviour that differs inside the Nix sandbox: # - docker_command_falls_back_after_timeout: expects docker (exit 127 = not found) # - local_command_timeout_returns_when_descendant_keeps_pipe_open: sandbox kills # descendant processes differently, so the expected error never arrives checkFlags = [ "--skip=commands::orchestrator::tests::docker_command_falls_back_after_timeout" "--skip=commands::orchestrator::tests::local_command_timeout_returns_when_descendant_keeps_pipe_open" ]; # cargo-tauri.hook: run `cargo tauri build` from this subdirectory tauriRoot = "apps/desktop"; # Override tauri config at build time: # - clear beforeBuildCommand (we run frontend + sidecars manually in preBuild) # - disable updater artifact generation (no auto-update in Nix packages) tauriBuildFlags = [ "--config" (builtins.toJSON { build.beforeBuildCommand = ""; bundle.createUpdaterArtifacts = false; }) "--no-sign" ]; preBuild = let target = stdenv.hostPlatform.rust.rustcTarget; in '' sidecarDir="$(pwd)/apps/desktop/src-tauri/sidecars" mkdir -p "$sidecarDir" # ── 1. openwork-server ──────────────────────────────────────────────── # Bun compiles TypeScript → self-contained native binary (no Bun runtime needed at runtime) ( cd apps/server bun ./script/build.ts --outdir "$sidecarDir" --filename openwork-server ) # script/build.ts names the output after the bun target when --target is given; # without --target it outputs just the filename. Rename to Tauri's expected triple format. mv "$sidecarDir/openwork-server" "$sidecarDir/openwork-server-${target}" # ── 2. opencode-router ──────────────────────────────────────────────── ( cd apps/opencode-router bun ./script/build.ts --outdir "$sidecarDir" --filename opencode-router ) mv "$sidecarDir/opencode-router" "$sidecarDir/opencode-router-${target}" # ── 3. openwork-orchestrator ────────────────────────────────────────── ( cd apps/orchestrator bun ./script/build.ts --outdir "$sidecarDir" --filename openwork-orchestrator ) mv "$sidecarDir/openwork-orchestrator" "$sidecarDir/openwork-orchestrator-${target}" # ── 4. chrome-devtools-mcp shim ─────────────────────────────────────── # This is a tiny TypeScript shim that proxies to `npm exec chrome-devtools-mcp`. # We compile it the same way as the other sidecars. bun build --compile apps/desktop/scripts/chrome-devtools-mcp-shim.ts \ --outfile "$sidecarDir/chrome-devtools-mcp-${target}" # ── 5. opencode binary (from Nix store) ─────────────────────────────── cp ${opencode}/bin/opencode "$sidecarDir/opencode-${target}" chmod +x "$sidecarDir/opencode-${target}" # ── 6. versions.json (required by Tauri; sha256 computed at build time) ─ oc_sha=$(sha256sum "$sidecarDir/opencode-${target}" | awk '{print $1}') sv_sha=$(sha256sum "$sidecarDir/openwork-server-${target}" | awk '{print $1}') rt_sha=$(sha256sum "$sidecarDir/opencode-router-${target}" | awk '{print $1}') or_sha=$(sha256sum "$sidecarDir/openwork-orchestrator-${target}" | awk '{print $1}') cd_sha=$(sha256sum "$sidecarDir/chrome-devtools-mcp-${target}" | awk '{print $1}') cat > "$sidecarDir/versions.json" <