fix(pilotdeck): build from source
CI / check (push) Has been cancelled

Replace the prebuilt Debian package with the documented source build. Build the web UI and gateway with pnpm, stage the pinned Cua driver, and start the web UI from the wrapper.
This commit is contained in:
2026-10-19 21:52:37 +03:00
parent fd74633e8d
commit a46a2bb967
2 changed files with 166 additions and 135 deletions
+164 -133
View File
@@ -1,182 +1,213 @@
{
lib,
stdenv,
fetchFromGitHub,
fetchurl,
dpkg,
autoPatchelfHook,
fetchPnpmDeps,
pnpmConfigHook,
nodejs_22,
nodejs-slim_22,
pnpm_10,
python3,
makeWrapper,
alsa-lib,
at-spi2-atk,
cairo,
cups,
dbus,
expat,
gdk-pixbuf,
glib,
gtk3,
gtk4,
libdrm,
libgbm,
libGL,
libnotify,
libpulseaudio,
libsecret,
ripgrep,
git,
curl,
procps,
bashInteractive,
coreutils,
findutils,
gnugrep,
gnused,
libx11,
libxcb,
libxcomposite,
libxdamage,
libxi,
libxtst,
libxext,
libxfixes,
libxkbcommon,
libxrandr,
libxshmfence,
nspr,
nss,
pango,
pciutils,
pipewire,
speechd-minimal,
systemd,
vulkan-loader,
wayland,
at-spi2-core,
}:
let
version = "2026.10.17";
# Release tags use dotted dates (v2026.10.17), but the Debian artifacts use
# the release date with a build suffix (2026.1017.0).
versionParts = lib.splitString "." version;
debVersion = "${lib.elemAt versionParts 0}.${lib.elemAt versionParts 1}${lib.elemAt versionParts 2}.0";
# Keep the source, LFS asset, pnpm dependency, and Cua driver hashes in
# sync with the upstream release when updating the version.
pnpm = pnpm_10.override { nodejs-slim = nodejs-slim_22; };
arch =
# Git LFS objects used by the web UI and the memory-core package. The
# upstream tarball contains pointer files, so fetch these paths through
# git-lfs and overlay them on the source tree.
lfsAssets = fetchFromGitHub {
owner = "OpenBMB";
repo = "PilotDeck";
tag = "v${version}";
fetchLFS = true;
sparseCheckout = [
"ui/public"
"src/context/memory/edgeclaw-memory-core/ui-source/assets"
];
hash = "sha256-R0bMxC6B2XqJMzuBnHmlNPX65tIwxL5FUc6Vv5M3O7w=";
};
cuaDriver =
{
x86_64-linux = "x64";
aarch64-linux = "arm64";
x86_64-linux = fetchurl {
url = "https://github.com/trycua/cua/releases/download/cua-driver-rs-v0.34.1/cua-driver-rs-0.34.1-linux-x86_64-binary.tar.gz";
hash = "sha256-pB/ivcvupFAdxZTAdPFrCXVyjgzHsIuQrOqFZNSPr+4=";
};
aarch64-linux = fetchurl {
url = "https://github.com/trycua/cua/releases/download/cua-driver-rs-v0.34.1/cua-driver-rs-0.34.1-linux-arm64-binary.tar.gz";
hash = "sha256-HIOdNUAbveog8+HPUKzpJu8Xvm8yzqfoIbArJjxJM9w=";
};
}
.${stdenv.hostPlatform.system}
or (throw "pilotdeck: unsupported system ${stdenv.hostPlatform.system}");
hashes = {
# The release publishes one Debian package per architecture. nix-update
# refreshes only the host architecture's hash; update the other one by hand
# from release.json in the GitHub release.
x86_64-linux = "sha256-vBqewHabntIz1hKbf10q9hkWX22m0U2mqJMXvX7cJOc=";
aarch64-linux = "sha256-paEEmWYkITfYTa3AsYD0WfVqtzzQ1GMlt5yjp7oXROY=";
};
runtimeLibs = [
alsa-lib
at-spi2-atk
cairo
cups
dbus
expat
gdk-pixbuf
glib
gtk3
gtk4
libdrm
libgbm
libGL
libnotify
libpulseaudio
libsecret
libx11
libxcb
libxcomposite
libxdamage
libxext
libxfixes
libxkbcommon
libxrandr
libxshmfence
nspr
nss
pango
pciutils
pipewire
speechd-minimal
stdenv.cc.cc.lib
systemd
vulkan-loader
];
in
stdenv.mkDerivation {
stdenv.mkDerivation (finalAttrs: {
pname = "pilotdeck";
inherit version;
src = fetchurl {
url = "https://github.com/OpenBMB/PilotDeck/releases/download/v${version}/PilotDeck-${debVersion}-linux-${arch}.deb";
hash = hashes.${stdenv.hostPlatform.system};
src = fetchFromGitHub {
owner = "OpenBMB";
repo = "PilotDeck";
tag = "v${version}";
hash = "sha256-VgsMoaaAtLIieBr4TchP61u5xV3PnVqjviak6DN7TPY=";
};
pnpmDeps = fetchPnpmDeps {
inherit (finalAttrs)
pname
version
src
;
inherit pnpm;
pnpmWorkspaces = [
"pilotdeck"
"pilotdeck-ui"
];
fetcherVersion = 4;
hash = "sha256-yhLx1PGSGoyds8lUe3cKpqMWgITwic5YTxugATARV7Y=";
};
pnpmWorkspaces = [
"pilotdeck"
"pilotdeck-ui"
];
nativeBuildInputs = [
dpkg
autoPatchelfHook
nodejs_22
pnpm
pnpmConfigHook
python3
makeWrapper
];
buildInputs = runtimeLibs;
env = {
# node-gyp must use the headers of the Node.js runtime that will execute
# the native addons, rather than downloading headers from nodejs.org.
npm_config_nodedir = nodejs_22;
npm_config_offline = "true";
pnpm_config_offline = "true";
};
# The Debian package contains the complete Electron application, including
# the bundled Node.js runtime and the built web UI.
unpackPhase = ''
runHook preUnpack
dpkg-deb --extract $src .
runHook postUnpack
postUnpack = ''
cp -r ${lfsAssets}/ui/public/. source/ui/public/
cp -r ${lfsAssets}/src/context/memory/edgeclaw-memory-core/ui-source/assets/. \
source/src/context/memory/edgeclaw-memory-core/ui-source/assets/
'';
dontBuild = true;
dontStrip = true;
preConfigure = ''
export HOME=$TMPDIR
'';
buildPhase = ''
runHook preBuild
# pnpmConfigHook installs dependencies with --ignore-scripts. Run the
# allowed lifecycle scripts now. better-sqlite3 and node-pty fall back to
# a source build when their prebuilt download is unavailable, while sharp
# uses its prebuilt @img/sharp-* optional dependency.
pnpm rebuild
pnpm --filter pilotdeck-ui rebuild
# The build script verifies and stages the pinned Cua computer-use driver.
# Point it at the Nix store instead of letting it download the archive.
export PILOTDECK_CUA_ARCHIVE=${cuaDriver}
pnpm run build:web
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/opt
cp -a opt/PilotDeck $out/opt/PilotDeck
mkdir -p $out/lib/pilotdeck
cp -r \
package.json \
tsconfig.json \
node_modules \
dist \
src \
scripts \
skills \
resources \
$out/lib/pilotdeck/
mkdir -p $out/share/applications
substitute usr/share/applications/pilotdeck-desktop.desktop \
$out/share/applications/pilotdeck.desktop \
--replace-fail 'Exec=/opt/PilotDeck/pilotdeck-desktop %U' 'Exec=pilotdeck %U' \
--replace-fail 'Icon=pilotdeck-desktop' 'Icon=pilotdeck'
mkdir -p $out/lib/pilotdeck/ui
cp -r \
ui/package.json \
ui/server \
ui/dist \
ui/public \
ui/scripts \
ui/shared \
ui/vite.config.js \
ui/node_modules \
$out/lib/pilotdeck/ui/
mkdir -p $out/share/icons/hicolor/256x256/apps
cp usr/share/icons/hicolor/256x256/apps/pilotdeck-desktop.png \
$out/share/icons/hicolor/256x256/apps/pilotdeck.png
makeWrapper $out/opt/PilotDeck/pilotdeck-desktop $out/bin/pilotdeck \
--prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath runtimeLibs}"
makeWrapper ${lib.getExe nodejs_22} $out/bin/pilotdeck \
--add-flags "$out/lib/pilotdeck/ui/server/webRuntimeSupervisor.js start-built" \
--prefix PATH : ${
lib.makeBinPath [
nodejs_22
ripgrep
git
curl
procps
bashInteractive
coreutils
findutils
gnugrep
gnused
]
} \
--prefix LD_LIBRARY_PATH : ${
lib.makeLibraryPath [
libx11
libxi
libxtst
libxext
libxkbcommon
wayland
at-spi2-core
stdenv.cc.cc.lib
]
}
runHook postInstall
'';
# bcrypt ships glibc and musl prebuilds side by side; only the glibc one is
# used here, so the musl libc reference of the other prebuild stays unresolved.
autoPatchelfIgnoreMissingDeps = [
"libc.musl-x86_64.so.1"
"libc.musl-aarch64.so.1"
];
passthru.category = "AI Agents";
passthru = {
category = "AI Agents";
updateScript = [
"nix-update"
"--flake"
".#pilotdeck"
];
};
meta = with lib; {
description = "Task-oriented AI Agent productivity platform";
meta = {
description = "Task-oriented AI Agent productivity platform (source-built web UI and gateway)";
homepage = "https://github.com/OpenBMB/PilotDeck";
changelog = "https://github.com/OpenBMB/PilotDeck/releases/tag/v${version}";
license = licenses.agpl3Only;
sourceProvenance = with sourceTypes; [ binaryNativeCode ];
license = lib.licenses.agpl3Only;
mainProgram = "pilotdeck";
platforms = [
"x86_64-linux"
"aarch64-linux"
];
};
}
})