From 3de5ecb7e90d017a070decffa4415d15448f48b2 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Wed, 20 May 2026 22:16:25 +0100 Subject: [PATCH 1/5] build: publish linux flatpak deb and rpm artifacts Restore Tauri Debian and RPM assets while adding Flatpak outputs for both desktop variants so Linux users have package-manager and sandboxed alternatives to AppImage. Electron Flatpak packaging now installs the required Freedesktop runtime in CI, and Tauri Flatpak packaging uses a generated manifest around the existing release binary and packaged resources. The Linux dependency list also includes xdg-utils because Tauri AppImage bundling requires xdg-open. Docker-based Ubuntu 24.04 reproductions verified Electron zip/AppImage creation and Tauri AppImage/deb/rpm creation. Local Docker could not complete Flatpak builds because bubblewrap cannot create/seccomp namespaces in this host container environment, which should not apply to native GitHub runners. --- .github/workflows/build-and-upload.yml | 36 ++++++- packages/electron-app/package.json | 19 ++++ packages/opencode-plugin/package.json | 2 +- packages/tauri-app/package.json | 1 + packages/tauri-app/scripts/build-flatpak.js | 107 ++++++++++++++++++++ scripts/desktop-server-resources.cjs | 2 +- 6 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 packages/tauri-app/scripts/build-flatpak.js diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml index 2dd971627..a703297ec 100644 --- a/.github/workflows/build-and-upload.yml +++ b/.github/workflows/build-and-upload.yml @@ -311,6 +311,16 @@ jobs: - name: Ensure rollup native binary run: npm install @rollup/rollup-linux-x64-gnu --no-save + - name: Install Flatpak build dependencies (Electron) + run: | + sudo apt-get update + sudo apt-get install -y flatpak flatpak-builder + sudo flatpak remote-add --system --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + sudo flatpak install --system --noninteractive flathub \ + org.freedesktop.Platform//24.08 \ + org.freedesktop.Sdk//24.08 \ + org.electronjs.Electron2.BaseApp//24.08 + - name: Build Linux binaries (Electron) run: npm run build:linux --workspace @neuralnomads/codenomad-electron-app @@ -322,7 +332,7 @@ jobs: run: | set -euo pipefail shopt -s nullglob - for file in packages/electron-app/release/*.zip packages/electron-app/release/*.AppImage; do + for file in packages/electron-app/release/*.zip packages/electron-app/release/*.AppImage packages/electron-app/release/*.flatpak; do [ -f "$file" ] || continue echo "Uploading $file" gh release upload "$TAG" "$file" --clobber @@ -336,6 +346,7 @@ jobs: path: | packages/electron-app/release/*.zip packages/electron-app/release/*.AppImage + packages/electron-app/release/*.flatpak retention-days: ${{ inputs.actions_artifacts_retention_days }} if-no-files-found: error @@ -637,7 +648,15 @@ jobs: libwebkit2gtk-4.1-dev \ libsoup-3.0-dev \ libayatana-appindicator3-dev \ - librsvg2-dev + librsvg2-dev \ + xdg-utils \ + rpm \ + flatpak \ + flatpak-builder + sudo flatpak remote-add --system --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + sudo flatpak install --system --noninteractive flathub \ + org.gnome.Platform//46 \ + org.gnome.Sdk//46 - name: Set workspace versions if: ${{ inputs.set_versions && inputs.version != '' }} @@ -673,6 +692,9 @@ jobs: working-directory: packages/tauri-app run: npm exec -- tauri build + - name: Build Flatpak bundle (Tauri) + run: npm run build:flatpak --workspace @codenomad/tauri-app + - name: Package Tauri artifacts (Linux) if: ${{ inputs.upload || inputs.upload_actions_artifacts }} run: | @@ -688,14 +710,20 @@ jobs: } appimage=$(find_one "*.AppImage") + deb=$(find_one "*.deb") + rpm=$(find_one "*.rpm") + flatpak=$(find_one "*.flatpak") fallback_bin="$SEARCH_ROOT/release/codenomad-tauri" - if [ -z "$appimage" ] || [ ! -f "$fallback_bin" ]; then - echo "Missing bundle(s): appimage=${appimage:-none} binary=$fallback_bin" >&2 + if [ -z "$appimage" ] || [ -z "$deb" ] || [ -z "$rpm" ] || [ -z "$flatpak" ] || [ ! -f "$fallback_bin" ]; then + echo "Missing bundle(s): appimage=${appimage:-none} deb=${deb:-none} rpm=${rpm:-none} flatpak=${flatpak:-none} binary=$fallback_bin" >&2 exit 1 fi cp "$appimage" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.AppImage" + cp "$deb" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.deb" + cp "$rpm" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.rpm" + cp "$flatpak" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.flatpak" zip -j "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.zip" "$fallback_bin" - name: Upload Actions artifacts (Tauri Linux) diff --git a/packages/electron-app/package.json b/packages/electron-app/package.json index f6a1fe753..038226bea 100644 --- a/packages/electron-app/package.json +++ b/packages/electron-app/package.json @@ -137,11 +137,30 @@ }, { "target": "AppImage" + }, + { + "target": "flatpak" } ], "artifactName": "CodeNomad-Electron-linux-${arch}-${version}.${ext}", "category": "Development", "icon": "electron/resources/icon.png" + }, + "flatpak": { + "runtimeVersion": "24.08", + "baseVersion": "24.08", + "branch": "stable", + "useWaylandFlags": true, + "finishArgs": [ + "--socket=wayland", + "--socket=x11", + "--share=ipc", + "--device=dri", + "--socket=pulseaudio", + "--filesystem=home", + "--share=network", + "--talk-name=org.freedesktop.Notifications" + ] } }, "private": true diff --git a/packages/opencode-plugin/package.json b/packages/opencode-plugin/package.json index a77516bb7..7c9d2cb78 100644 --- a/packages/opencode-plugin/package.json +++ b/packages/opencode-plugin/package.json @@ -10,7 +10,7 @@ "README.md" ], "scripts": { - "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json" + "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && npm exec -- tsc -p tsconfig.json" }, "dependencies": { "@opencode-ai/plugin": "1.3.7" diff --git a/packages/tauri-app/package.json b/packages/tauri-app/package.json index 590a3a4cb..d496c9257 100644 --- a/packages/tauri-app/package.json +++ b/packages/tauri-app/package.json @@ -11,6 +11,7 @@ "sync:version": "node ./scripts/sync-tauri-version.js", "prebuild": "node ./scripts/prebuild.js", "bundle:server": "npm run prebuild", + "build:flatpak": "node ./scripts/build-flatpak.js", "build": "tauri build", "smoke:resources": "node ../../scripts/smoke-packaged-resources.cjs --resources src-tauri/resources --loading src-tauri/resources/ui-loading" }, diff --git a/packages/tauri-app/scripts/build-flatpak.js b/packages/tauri-app/scripts/build-flatpak.js new file mode 100644 index 000000000..413a637fd --- /dev/null +++ b/packages/tauri-app/scripts/build-flatpak.js @@ -0,0 +1,107 @@ +#!/usr/bin/env node +const fs = require("fs") +const path = require("path") +const { spawnSync } = require("child_process") + +const root = path.resolve(__dirname, "..") +const workspaceRoot = path.resolve(root, "..", "..") +const version = process.env.VERSION || require(path.join(root, "package.json")).version +const appId = "ai.neuralnomads.codenomad.client" +const buildRoot = path.join(root, "target", "flatpak") +const stagingRoot = path.join(buildRoot, "staging") +const repoRoot = path.join(buildRoot, "repo") +const flatpakBuildRoot = path.join(buildRoot, "build") +const manifestPath = path.join(buildRoot, `${appId}.json`) +const artifactDir = path.join(root, "target", "release", "bundle", "flatpak") +const artifactPath = path.join(artifactDir, `CodeNomad-Tauri-linux-x64-${version}.flatpak`) + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { stdio: "inherit", ...options }) + if (result.error) throw result.error + if (result.status !== 0) { + throw new Error(`${command} ${args.join(" ")} exited with code ${result.status || 1}`) + } +} + +function copyRequired(from, to) { + if (!fs.existsSync(from)) { + throw new Error(`Missing required Flatpak input: ${from}`) + } + fs.cpSync(from, to, { recursive: true, dereference: true }) +} + +fs.rmSync(buildRoot, { recursive: true, force: true }) +fs.mkdirSync(stagingRoot, { recursive: true }) +fs.mkdirSync(artifactDir, { recursive: true }) + +copyRequired(path.join(root, "target", "release", "codenomad-tauri"), path.join(stagingRoot, "codenomad-tauri")) +copyRequired(path.join(root, "target", "release", "resources"), path.join(stagingRoot, "resources")) +copyRequired( + path.join(root, "src-tauri", "icons", "linux", "512x512.png"), + path.join(stagingRoot, `${appId}.png`), +) + +const desktopFile = [ + "[Desktop Entry]", + "Type=Application", + "Name=CodeNomad", + "Comment=AI coding assistant", + "Categories=Development;IDE;", + "Exec=codenomad-tauri", + `Icon=${appId}`, + "Terminal=false", + "", +].join("\n") +fs.writeFileSync(path.join(stagingRoot, `${appId}.desktop`), desktopFile) + +const manifest = { + "app-id": appId, + runtime: "org.gnome.Platform", + "runtime-version": "46", + sdk: "org.gnome.Sdk", + branch: "stable", + command: "codenomad-tauri", + "finish-args": [ + "--socket=wayland", + "--socket=x11", + "--share=ipc", + "--device=dri", + "--socket=pulseaudio", + "--filesystem=home", + "--share=network", + "--talk-name=org.freedesktop.Notifications", + ], + modules: [ + { + name: "codenomad-tauri", + "buildsystem": "simple", + "build-commands": [ + "install -Dm755 codenomad-tauri /app/bin/codenomad-tauri", + "mkdir -p /app/lib/CodeNomad", + "cp -a resources /app/lib/CodeNomad/resources", + `install -Dm644 ${appId}.desktop /app/share/applications/${appId}.desktop`, + `install -Dm644 ${appId}.png /app/share/icons/hicolor/512x512/apps/${appId}.png`, + ], + sources: [ + { + type: "dir", + path: stagingRoot, + }, + ], + }, + ], +} + +fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`) +fs.rmSync(repoRoot, { recursive: true, force: true }) +fs.rmSync(flatpakBuildRoot, { recursive: true, force: true }) +fs.rmSync(artifactPath, { force: true }) + +run("flatpak-builder", ["--force-clean", `--repo=${repoRoot}`, flatpakBuildRoot, manifestPath], { + cwd: workspaceRoot, +}) +run("flatpak", ["build-bundle", repoRoot, artifactPath, appId, "stable"], { + cwd: workspaceRoot, +}) + +console.log(`[flatpak] wrote ${artifactPath}`) diff --git a/scripts/desktop-server-resources.cjs b/scripts/desktop-server-resources.cjs index 000219cdd..c906b5a88 100644 --- a/scripts/desktop-server-resources.cjs +++ b/scripts/desktop-server-resources.cjs @@ -23,7 +23,7 @@ function copyRequiredArtifact(serverRoot, serverDest, name, log) { if (!fs.existsSync(from)) { throw new Error(`Missing required server artifact: ${from}`) } - fs.cpSync(from, to, { recursive: true, dereference: true }) + fs.cpSync(from, to, { recursive: true }) log(`copied ${name}`) } From b919efcf26df61f9a058492d3ef1c51a000ad33d Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Thu, 21 May 2026 09:28:53 +0100 Subject: [PATCH 2/5] build: verify linux flatpak artifacts Add explicit Electron Linux artifact gating so the release job fails if Flatpak output is missing rather than silently uploading only zip/AppImage assets. Reuse the existing Tauri Linux desktop metadata for Flatpak packaging to avoid drift across deb, rpm, AppImage, and Flatpak launchers. The workflow now installs the generated Tauri Flatpak and runs ldd inside the sandbox to catch missing runtime libraries before upload. --- .github/workflows/build-and-upload.yml | 36 +++++++++++++++++++++ packages/tauri-app/scripts/build-flatpak.js | 19 +++-------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml index a703297ec..982bb7e71 100644 --- a/.github/workflows/build-and-upload.yml +++ b/.github/workflows/build-and-upload.yml @@ -327,6 +327,18 @@ jobs: - name: Verify bundled Node resource (Electron Linux) run: node scripts/verify-bundled-node.cjs packages/electron-app/electron/resources@linux-x64 + - name: Verify Electron Linux artifacts + run: | + set -euo pipefail + shopt -s nullglob + zips=(packages/electron-app/release/*.zip) + appimages=(packages/electron-app/release/*.AppImage) + flatpaks=(packages/electron-app/release/*.flatpak) + if [ "${#zips[@]}" -eq 0 ] || [ "${#appimages[@]}" -eq 0 ] || [ "${#flatpaks[@]}" -eq 0 ]; then + echo "Missing Electron Linux artifact(s): zip=${#zips[@]} appimage=${#appimages[@]} flatpak=${#flatpaks[@]}" >&2 + exit 1 + fi + - name: Upload release assets if: ${{ inputs.upload && inputs.tag != '' }} run: | @@ -695,6 +707,30 @@ jobs: - name: Build Flatpak bundle (Tauri) run: npm run build:flatpak --workspace @codenomad/tauri-app + - name: Verify Tauri Flatpak runtime closure + run: | + set -euo pipefail + shopt -s nullglob + flatpaks=(packages/tauri-app/target/release/bundle/flatpak/*.flatpak) + if [ "${#flatpaks[@]}" -eq 0 ]; then + echo "Missing Tauri Flatpak artifact" >&2 + exit 1 + fi + + flatpak install --user --noninteractive --bundle "${flatpaks[0]}" + cleanup() { + flatpak uninstall --user --noninteractive ai.neuralnomads.codenomad.client >/dev/null 2>&1 || true + } + trap cleanup EXIT + + flatpak run --user --command=sh ai.neuralnomads.codenomad.client -c ' + set -e + test -x /app/bin/codenomad-tauri + test -d /app/lib/CodeNomad/resources + ldd /app/bin/codenomad-tauri | tee /tmp/codenomad-tauri-ldd.txt + ! grep -q "not found" /tmp/codenomad-tauri-ldd.txt + ' + - name: Package Tauri artifacts (Linux) if: ${{ inputs.upload || inputs.upload_actions_artifacts }} run: | diff --git a/packages/tauri-app/scripts/build-flatpak.js b/packages/tauri-app/scripts/build-flatpak.js index 413a637fd..8e36a5f37 100644 --- a/packages/tauri-app/scripts/build-flatpak.js +++ b/packages/tauri-app/scripts/build-flatpak.js @@ -14,6 +14,7 @@ const flatpakBuildRoot = path.join(buildRoot, "build") const manifestPath = path.join(buildRoot, `${appId}.json`) const artifactDir = path.join(root, "target", "release", "bundle", "flatpak") const artifactPath = path.join(artifactDir, `CodeNomad-Tauri-linux-x64-${version}.flatpak`) +const desktopSource = path.join(root, "src-tauri", "icons", "linux", `${appId}.desktop`) function run(command, args, options = {}) { const result = spawnSync(command, args, { stdio: "inherit", ...options }) @@ -38,21 +39,9 @@ copyRequired(path.join(root, "target", "release", "codenomad-tauri"), path.join( copyRequired(path.join(root, "target", "release", "resources"), path.join(stagingRoot, "resources")) copyRequired( path.join(root, "src-tauri", "icons", "linux", "512x512.png"), - path.join(stagingRoot, `${appId}.png`), + path.join(stagingRoot, "codenomad-tauri.png"), ) - -const desktopFile = [ - "[Desktop Entry]", - "Type=Application", - "Name=CodeNomad", - "Comment=AI coding assistant", - "Categories=Development;IDE;", - "Exec=codenomad-tauri", - `Icon=${appId}`, - "Terminal=false", - "", -].join("\n") -fs.writeFileSync(path.join(stagingRoot, `${appId}.desktop`), desktopFile) +copyRequired(desktopSource, path.join(stagingRoot, `${appId}.desktop`)) const manifest = { "app-id": appId, @@ -80,7 +69,7 @@ const manifest = { "mkdir -p /app/lib/CodeNomad", "cp -a resources /app/lib/CodeNomad/resources", `install -Dm644 ${appId}.desktop /app/share/applications/${appId}.desktop`, - `install -Dm644 ${appId}.png /app/share/icons/hicolor/512x512/apps/${appId}.png`, + "install -Dm644 codenomad-tauri.png /app/share/icons/hicolor/512x512/apps/codenomad-tauri.png", ], sources: [ { From a81f7bc0fedf9766d95803a05f4eeaff43beb722 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Thu, 21 May 2026 10:26:21 +0100 Subject: [PATCH 3/5] build: stabilize linux flatpak packaging Move Electron Flatpak packaging out of electron-builder's bundled flatpak target and into a repository-controlled flatpak-builder manifest generated from the linux-unpacked app. This keeps the zip and AppImage build path unchanged while producing an explicit .flatpak artifact after electron-builder completes. Bump the Tauri Flatpak runtime from GNOME 46 to GNOME 47 so the Ubuntu 24.04-built binary can satisfy its GLIBC_2.39 runtime dependency during the CI install smoke check. Validation: node --check for both Flatpak scripts, JSON parse for the Electron package, Ruby YAML parse for the workflow, and git diff --check. --- .github/workflows/build-and-upload.yml | 10 +- packages/electron-app/package.json | 20 +-- .../electron-app/scripts/build-flatpak.js | 119 ++++++++++++++++++ packages/tauri-app/scripts/build-flatpak.js | 2 +- 4 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 packages/electron-app/scripts/build-flatpak.js diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml index 982bb7e71..4b8f4c518 100644 --- a/.github/workflows/build-and-upload.yml +++ b/.github/workflows/build-and-upload.yml @@ -318,12 +318,14 @@ jobs: sudo flatpak remote-add --system --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo sudo flatpak install --system --noninteractive flathub \ org.freedesktop.Platform//24.08 \ - org.freedesktop.Sdk//24.08 \ - org.electronjs.Electron2.BaseApp//24.08 + org.freedesktop.Sdk//24.08 - name: Build Linux binaries (Electron) run: npm run build:linux --workspace @neuralnomads/codenomad-electron-app + - name: Build Flatpak bundle (Electron) + run: npm run build:flatpak --workspace @neuralnomads/codenomad-electron-app + - name: Verify bundled Node resource (Electron Linux) run: node scripts/verify-bundled-node.cjs packages/electron-app/electron/resources@linux-x64 @@ -667,8 +669,8 @@ jobs: flatpak-builder sudo flatpak remote-add --system --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo sudo flatpak install --system --noninteractive flathub \ - org.gnome.Platform//46 \ - org.gnome.Sdk//46 + org.gnome.Platform//47 \ + org.gnome.Sdk//47 - name: Set workspace versions if: ${{ inputs.set_versions && inputs.version != '' }} diff --git a/packages/electron-app/package.json b/packages/electron-app/package.json index 038226bea..74909621b 100644 --- a/packages/electron-app/package.json +++ b/packages/electron-app/package.json @@ -34,6 +34,7 @@ "build:linux": "node scripts/build.js linux", "build:linux-arm64": "node scripts/build.js linux-arm64", "build:linux-rpm": "node scripts/build.js linux-rpm", + "build:flatpak": "node scripts/build-flatpak.js", "build:all": "node scripts/build.js all", "package:mac": "node scripts/build.js mac", "package:win": "node scripts/build.js win", @@ -137,30 +138,11 @@ }, { "target": "AppImage" - }, - { - "target": "flatpak" } ], "artifactName": "CodeNomad-Electron-linux-${arch}-${version}.${ext}", "category": "Development", "icon": "electron/resources/icon.png" - }, - "flatpak": { - "runtimeVersion": "24.08", - "baseVersion": "24.08", - "branch": "stable", - "useWaylandFlags": true, - "finishArgs": [ - "--socket=wayland", - "--socket=x11", - "--share=ipc", - "--device=dri", - "--socket=pulseaudio", - "--filesystem=home", - "--share=network", - "--talk-name=org.freedesktop.Notifications" - ] } }, "private": true diff --git a/packages/electron-app/scripts/build-flatpak.js b/packages/electron-app/scripts/build-flatpak.js new file mode 100644 index 000000000..8947c8322 --- /dev/null +++ b/packages/electron-app/scripts/build-flatpak.js @@ -0,0 +1,119 @@ +#!/usr/bin/env node + +import fs from "fs" +import path from "path" +import { spawnSync } from "child_process" +import { fileURLToPath } from "url" + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const root = path.resolve(__dirname, "..") +const workspaceRoot = path.resolve(root, "..", "..") +const version = process.env.VERSION || JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")).version +const appId = "ai.neuralnomads.codenomad.client" +const releaseRoot = path.join(root, "release") +const appSource = path.join(releaseRoot, "linux-unpacked") +const buildRoot = path.join(root, "target", "flatpak") +const stagingRoot = path.join(buildRoot, "staging") +const repoRoot = path.join(buildRoot, "repo") +const flatpakBuildRoot = path.join(buildRoot, "build") +const manifestPath = path.join(buildRoot, `${appId}.electron.json`) +const artifactPath = path.join(releaseRoot, `CodeNomad-Electron-linux-x64-${version}.flatpak`) + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { stdio: "inherit", ...options }) + if (result.error) throw result.error + if (result.status !== 0) { + throw new Error(`${command} ${args.join(" ")} exited with code ${result.status || 1}`) + } +} + +function copyRequired(from, to) { + if (!fs.existsSync(from)) { + throw new Error(`Missing required Flatpak input: ${from}`) + } + fs.cpSync(from, to, { recursive: true, dereference: true }) +} + +fs.rmSync(buildRoot, { recursive: true, force: true }) +fs.mkdirSync(stagingRoot, { recursive: true }) +fs.mkdirSync(releaseRoot, { recursive: true }) + +copyRequired(appSource, path.join(stagingRoot, "CodeNomad")) +copyRequired(path.join(root, "electron", "resources", "icon.png"), path.join(stagingRoot, `${appId}.png`)) + +fs.writeFileSync( + path.join(stagingRoot, `${appId}.desktop`), + [ + "[Desktop Entry]", + "Type=Application", + "Name=CodeNomad", + "Exec=codenomad-electron", + `Icon=${appId}`, + "Terminal=false", + "Categories=Development;IDE;", + "StartupWMClass=CodeNomad", + "", + ].join("\n"), +) + +fs.writeFileSync( + path.join(stagingRoot, "codenomad-electron"), + [ + "#!/bin/sh", + "exec /app/CodeNomad/CodeNomad \"$@\"", + "", + ].join("\n"), + { mode: 0o755 }, +) + +const manifest = { + "app-id": appId, + runtime: "org.freedesktop.Platform", + "runtime-version": "24.08", + sdk: "org.freedesktop.Sdk", + branch: "stable", + command: "codenomad-electron", + "finish-args": [ + "--socket=wayland", + "--socket=x11", + "--share=ipc", + "--device=dri", + "--socket=pulseaudio", + "--filesystem=home", + "--share=network", + "--talk-name=org.freedesktop.Notifications", + ], + modules: [ + { + name: "codenomad-electron", + buildsystem: "simple", + "build-commands": [ + "mkdir -p /app/CodeNomad", + "cp -a CodeNomad/. /app/CodeNomad/", + "install -Dm755 codenomad-electron /app/bin/codenomad-electron", + `install -Dm644 ${appId}.desktop /app/share/applications/${appId}.desktop`, + `install -Dm644 ${appId}.png /app/share/icons/hicolor/512x512/apps/${appId}.png`, + ], + sources: [ + { + type: "dir", + path: stagingRoot, + }, + ], + }, + ], +} + +fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`) +fs.rmSync(repoRoot, { recursive: true, force: true }) +fs.rmSync(flatpakBuildRoot, { recursive: true, force: true }) +fs.rmSync(artifactPath, { force: true }) + +run("flatpak-builder", ["--force-clean", `--repo=${repoRoot}`, flatpakBuildRoot, manifestPath], { + cwd: workspaceRoot, +}) +run("flatpak", ["build-bundle", repoRoot, artifactPath, appId, "stable"], { + cwd: workspaceRoot, +}) + +console.log(`[flatpak] wrote ${artifactPath}`) diff --git a/packages/tauri-app/scripts/build-flatpak.js b/packages/tauri-app/scripts/build-flatpak.js index 8e36a5f37..8f415faf7 100644 --- a/packages/tauri-app/scripts/build-flatpak.js +++ b/packages/tauri-app/scripts/build-flatpak.js @@ -46,7 +46,7 @@ copyRequired(desktopSource, path.join(stagingRoot, `${appId}.desktop`)) const manifest = { "app-id": appId, runtime: "org.gnome.Platform", - "runtime-version": "46", + "runtime-version": "47", sdk: "org.gnome.Sdk", branch: "stable", command: "codenomad-tauri", From 14dd18fded146e7b322b6411bada9feb6a183f93 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Thu, 21 May 2026 10:48:23 +0100 Subject: [PATCH 4/5] build: use valid electron flatpak icon Install the existing 512x512 PWA icon into the Electron Flatpak hicolor 512x512 location instead of the 1024x1024 application icon. Flatpak export validates icon dimensions against the target icon directory and rejected the previous artifact. Validation: node --check packages/electron-app/scripts/build-flatpak.js and git diff --check. --- packages/electron-app/scripts/build-flatpak.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/electron-app/scripts/build-flatpak.js b/packages/electron-app/scripts/build-flatpak.js index 8947c8322..f1925ba0f 100644 --- a/packages/electron-app/scripts/build-flatpak.js +++ b/packages/electron-app/scripts/build-flatpak.js @@ -39,7 +39,7 @@ fs.mkdirSync(stagingRoot, { recursive: true }) fs.mkdirSync(releaseRoot, { recursive: true }) copyRequired(appSource, path.join(stagingRoot, "CodeNomad")) -copyRequired(path.join(root, "electron", "resources", "icon.png"), path.join(stagingRoot, `${appId}.png`)) +copyRequired(path.join(root, "electron", "resources", "server", "public", "pwa-512x512.png"), path.join(stagingRoot, `${appId}.png`)) fs.writeFileSync( path.join(stagingRoot, `${appId}.desktop`), From 7e1856eba37bfd91a818fa75551a15ae3bc63790 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Sun, 24 May 2026 07:18:47 +0100 Subject: [PATCH 5/5] build: preserve tauri artifact versions in pr builds Use the Tauri package version when the reusable PR build workflow does not provide VERSION. PR validation intentionally leaves release version inputs empty, but artifact filenames should still include the package version rather than producing names like CodeNomad-Tauri-linux-x64-.flatpak. Validation: Ruby YAML parse for the workflow and git diff --check. --- .github/workflows/build-and-upload.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml index 4b8f4c518..5b627dbcb 100644 --- a/.github/workflows/build-and-upload.yml +++ b/.github/workflows/build-and-upload.yml @@ -739,6 +739,10 @@ jobs: set -euo pipefail SEARCH_ROOT="packages/tauri-app/target" ARTIFACT_DIR="packages/tauri-app/release-tauri" + VERSION_TO_USE="${VERSION:-}" + if [ -z "$VERSION_TO_USE" ]; then + VERSION_TO_USE=$(node -p "require('./packages/tauri-app/package.json').version") + fi rm -rf "$ARTIFACT_DIR" mkdir -p "$ARTIFACT_DIR" shopt -s nullglob globstar @@ -758,11 +762,11 @@ jobs: exit 1 fi - cp "$appimage" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.AppImage" - cp "$deb" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.deb" - cp "$rpm" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.rpm" - cp "$flatpak" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.flatpak" - zip -j "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION}.zip" "$fallback_bin" + cp "$appimage" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION_TO_USE}.AppImage" + cp "$deb" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION_TO_USE}.deb" + cp "$rpm" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION_TO_USE}.rpm" + cp "$flatpak" "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION_TO_USE}.flatpak" + zip -j "$ARTIFACT_DIR/CodeNomad-Tauri-linux-x64-${VERSION_TO_USE}.zip" "$fallback_bin" - name: Upload Actions artifacts (Tauri Linux) if: ${{ inputs.upload_actions_artifacts }}