feat(aionui): Add AionUi AI cowork desktop app (v2.1.4)
Some checks failed
CI / check (push) Has been cancelled
Some checks failed
CI / check (push) Has been cancelled
Build AionUi from source using bun for dependency fetching and electron-vite for TypeScript compilation. Native addons (better-sqlite3, sharp) are compiled against nixpkgs node-gyp. The package uses a fixed-output derivation for bun install, electron-vite for the build, and wraps the result with nixpkgs electron for a fully self-contained runtime. Also includes desktop entry and icon generation.
This commit is contained in:
5
packages/aionui/default.nix
Normal file
5
packages/aionui/default.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
pkgs.callPackage ./package.nix { }
|
||||
226
packages/aionui/package.nix
Normal file
226
packages/aionui/package.nix
Normal file
@@ -0,0 +1,226 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
bun,
|
||||
nodejs,
|
||||
node-gyp,
|
||||
electron,
|
||||
autoPatchelfHook,
|
||||
makeWrapper,
|
||||
copyDesktopItems,
|
||||
imagemagick,
|
||||
python3,
|
||||
cacert,
|
||||
}:
|
||||
|
||||
let
|
||||
version = "2.1.4";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "iOfficeAI";
|
||||
repo = "AionUi";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-A7dKGEuo5n+M7D9fJR3TN95q1P7En/ulsTO+ev6SAUY=";
|
||||
};
|
||||
|
||||
# Fixed-output derivation: fetch all pure-JS dependencies via bun.
|
||||
# We skip install scripts because they use #!/usr/bin/env shebangs
|
||||
# that don't exist in the Nix sandbox. Native addons are built
|
||||
# separately in the main derivation.
|
||||
bunDeps = stdenv.mkDerivation {
|
||||
name = "aionui-bun-deps-${version}";
|
||||
inherit src;
|
||||
nativeBuildInputs = [
|
||||
bun
|
||||
cacert
|
||||
];
|
||||
|
||||
outputHashAlgo = "sha256";
|
||||
outputHashMode = "recursive";
|
||||
outputHash = "sha256-Fuj55vxDgpx5A4iwnU/5IZKPfaYMH3DeZ1yauuZHn8g=";
|
||||
|
||||
dontPatchShebangs = true;
|
||||
dontFixup = true;
|
||||
|
||||
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
|
||||
buildPhase = ''
|
||||
export HOME=$TMPDIR
|
||||
bun install --frozen-lockfile --ignore-scripts
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r node_modules $out/
|
||||
cp -r packages $out/
|
||||
# Workspace packages reference root configs with relative paths
|
||||
cp tsconfig.json $out/
|
||||
'';
|
||||
};
|
||||
in
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "aionui";
|
||||
inherit version src;
|
||||
|
||||
nativeBuildInputs = [
|
||||
bun
|
||||
nodejs
|
||||
node-gyp
|
||||
autoPatchelfHook
|
||||
makeWrapper
|
||||
copyDesktopItems
|
||||
imagemagick
|
||||
python3
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
stdenv.cc.cc.lib
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
export HOME=$TMPDIR
|
||||
|
||||
# Use the pre-fetched node_modules from the FOD (symlink farm)
|
||||
ln -sf ${bunDeps}/node_modules .
|
||||
|
||||
# ── Build better-sqlite3 native addon ──────────────────────
|
||||
# The FOD output is read-only; build in a temp dir.
|
||||
echo "Building better-sqlite3 from source..."
|
||||
BT3_SRC=$TMPDIR/bts3-src
|
||||
BT3_OUT=$TMPDIR/bts3-out
|
||||
mkdir -p "$BT3_SRC" "$BT3_OUT"
|
||||
cp -rL node_modules/better-sqlite3/* "$BT3_SRC/"
|
||||
chmod -R u+w "$BT3_SRC"
|
||||
(
|
||||
cd "$BT3_SRC"
|
||||
export npm_config_nodedir=${nodejs}
|
||||
node-gyp rebuild
|
||||
mkdir -p "$BT3_OUT/build/Release"
|
||||
cp build/Release/better_sqlite3.node "$BT3_OUT/build/Release/" 2>/dev/null || true
|
||||
)
|
||||
|
||||
# ── Build sharp native addon ──────────────────────────────
|
||||
echo "Building sharp from source..."
|
||||
SHARP_SRC=$TMPDIR/sharp-src
|
||||
SHARP_OUT=$TMPDIR/sharp-out
|
||||
mkdir -p "$SHARP_SRC" "$SHARP_OUT"
|
||||
cp -rL node_modules/sharp/* "$SHARP_SRC/" 2>/dev/null || true
|
||||
if [ -f "$SHARP_SRC/package.json" ]; then
|
||||
chmod -R u+w "$SHARP_SRC"
|
||||
(
|
||||
cd "$SHARP_SRC"
|
||||
export npm_config_nodedir=${nodejs}
|
||||
node-gyp rebuild 2>/dev/null || echo " sharp: build skipped (needs libvips)"
|
||||
mkdir -p "$SHARP_OUT/build/Release"
|
||||
cp build/Release/sharp.node "$SHARP_OUT/build/Release/" 2>/dev/null || true
|
||||
)
|
||||
fi
|
||||
|
||||
# ── electron-vite build ───────────────────────────────────
|
||||
echo "Running electron-vite build..."
|
||||
${nodejs}/bin/node node_modules/.bin/electron-vite build \
|
||||
--config packages/desktop/electron.vite.config.ts
|
||||
|
||||
# ── Bundle MCP servers ────────────────────────────────────
|
||||
echo "Building MCP servers..."
|
||||
${nodejs}/bin/node scripts/build-mcp-servers.js
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/{bin,lib/aionui}
|
||||
|
||||
# ── Built output ──────────────────────────────────────────
|
||||
cp -r out $out/lib/aionui/
|
||||
cp -r public $out/lib/aionui/
|
||||
cp package.json $out/lib/aionui/
|
||||
|
||||
# ── Runtime dependencies ──────────────────────────────────
|
||||
# Copy node_modules (from the symlink) – the compiled output
|
||||
# has externalized require() calls for every dependency.
|
||||
cp -rL node_modules $out/lib/aionui/
|
||||
|
||||
# Remove prebuilt musl (Alpine) binaries from sharp — they
|
||||
# are incompatible with glibc and we built from source anyway.
|
||||
find $out/lib/aionui/node_modules -path "*/sharp-linuxmusl*" -type d -exec rm -rf {} + 2>/dev/null || true
|
||||
find $out/lib/aionui/node_modules -path "*/sharp-libvips-linuxmusl*" -type d -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
# ── Inject compiled native addons ─────────────────────────
|
||||
# cp -rL from the FOD preserves read-only permissions.
|
||||
# Make native addon dirs writable before overlaying binaries.
|
||||
chmod -R u+w $out/lib/aionui/node_modules/better-sqlite3 2>/dev/null || true
|
||||
chmod -R u+w $out/lib/aionui/node_modules/sharp 2>/dev/null || true
|
||||
|
||||
BT3_OUT=$TMPDIR/bts3-out
|
||||
if [ -f "$BT3_OUT/build/Release/better_sqlite3.node" ]; then
|
||||
mkdir -p $out/lib/aionui/node_modules/better-sqlite3/build/Release
|
||||
cp "$BT3_OUT/build/Release/better_sqlite3.node" \
|
||||
$out/lib/aionui/node_modules/better-sqlite3/build/Release/
|
||||
fi
|
||||
|
||||
SHARP_OUT=$TMPDIR/sharp-out
|
||||
if [ -f "$SHARP_OUT/build/Release/sharp.node" ]; then
|
||||
mkdir -p $out/lib/aionui/node_modules/sharp/build/Release
|
||||
cp "$SHARP_OUT/build/Release/sharp.node" \
|
||||
$out/lib/aionui/node_modules/sharp/build/Release/
|
||||
fi
|
||||
|
||||
# ── Desktop entry ─────────────────────────────────────────
|
||||
mkdir -p $out/share/applications
|
||||
cat > $out/share/applications/aionui.desktop << EOF
|
||||
[Desktop Entry]
|
||||
Name=AionUi
|
||||
Comment=Free, open-source Cowork app with AI Agents
|
||||
Exec=$out/bin/aionui
|
||||
Icon=aionui
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Office;Utility;
|
||||
EOF
|
||||
|
||||
mkdir -p $out/share/icons/hicolor/256x256/apps
|
||||
if [ -f resources/app.png ]; then
|
||||
convert resources/app.png -resize 256x256 \
|
||||
$out/share/icons/hicolor/256x256/apps/aionui.png
|
||||
fi
|
||||
|
||||
# ── Launcher ──────────────────────────────────────────────
|
||||
makeWrapper ${electron}/bin/electron $out/bin/aionui \
|
||||
--add-flags "$out/lib/aionui"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
dontStrip = true;
|
||||
autoPatchelfIgnoreMissingDeps = true;
|
||||
|
||||
desktopItems = [ "aionui.desktop" ];
|
||||
|
||||
doCheck = false;
|
||||
|
||||
passthru = {
|
||||
category = "AI Coding Agents";
|
||||
updateScript = [
|
||||
"nix-update"
|
||||
"--flake"
|
||||
".#aionui"
|
||||
];
|
||||
};
|
||||
|
||||
meta = with lib; {
|
||||
description = "Free, open-source, Cowork app with AI Agents";
|
||||
homepage = "https://github.com/iOfficeAI/AionUi";
|
||||
changelog = "https://github.com/iOfficeAI/AionUi/releases/tag/v${version}";
|
||||
license = licenses.asl20;
|
||||
sourceProvenance = with sourceTypes; [ fromSource ];
|
||||
mainProgram = "aionui";
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user