diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7848f06..e8f96386 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -315,9 +315,9 @@ jobs: # Linux is a shipped target from this change on. Same reasoning as # build-windows: `cargo test --lib` proves the crate compiles, not that an - # AppImage and a deb come out. The name assertions match the exact filenames - # release.yml's verification step requires, so a bundler naming change fails - # here rather than after a tag is pushed. + # AppImage, a deb and an rpm come out. The name assertions match the exact + # filenames release.yml's verification step requires, so a bundler naming + # change fails here rather than after a tag is pushed. build-linux: name: build-linux # 24.04, not 22.04: the ONNX Runtime binary fastembed downloads is built @@ -366,8 +366,24 @@ jobs: - name: Install deps run: npm ci + # Tauri fetches its own linuxdeploy, a July 2024 build, into ~/.cache/tauri + # and reuses whatever is there. That build still copies Ubuntu's + # libwayland-client into the AppImage, and Fedora's and Arch's Mesa need + # a symbol from a newer one, so the WebKit web process aborted with + # "Could not create default EGL display" and the window stayed white + # (#130). linuxdeploy excludes the library since November 2024; seed the + # cache with a release that has it, pinned by checksum. + - name: Use a linuxdeploy that leaves libwayland-client to the host + run: | + set -euo pipefail + mkdir -p ~/.cache/tauri + curl -fsSL -o ~/.cache/tauri/linuxdeploy-x86_64.AppImage \ + https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20251107-1/linuxdeploy-x86_64.AppImage + echo "c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d $HOME/.cache/tauri/linuxdeploy-x86_64.AppImage" | sha256sum -c + chmod +x ~/.cache/tauri/linuxdeploy-x86_64.AppImage + - name: Build app and bundles - run: npx tauri build --config src-tauri/tauri.ci.conf.json --bundles appimage deb + run: npx tauri build --config src-tauri/tauri.ci.conf.json --bundles appimage deb rpm - name: Assert bundles exist with the names the release expects run: | @@ -376,7 +392,117 @@ jobs: version=$(node -p "require('./package.json').version") appimage="$root/appimage/Moldavite_${version}_amd64.AppImage" deb="$root/deb/Moldavite_${version}_amd64.deb" - ls -la "$root/appimage" "$root/deb" || true + rpm="$root/rpm/Moldavite-${version}-1.x86_64.rpm" + ls -la "$root/appimage" "$root/deb" "$root/rpm" || true [ -f "$appimage" ] || { echo "::error::Expected $appimage"; exit 1; } [ -f "$deb" ] || { echo "::error::Expected $deb"; exit 1; } - du -h "$appimage" "$deb" + [ -f "$rpm" ] || { echo "::error::Expected $rpm"; exit 1; } + du -h "$appimage" "$deb" "$rpm" + # The host's Mesa resolves against libwayland-client; a bundled copy + # is the #130 blank window on Fedora and Arch. + extracted=$(mktemp -d) + (cd "$extracted" && "$GITHUB_WORKSPACE/$appimage" --appimage-extract >/dev/null) + if find "$extracted/squashfs-root" -name 'libwayland-client.so*' | grep -q .; then + echo "::error::The AppImage bundles libwayland-client (#130)"; exit 1 + fi + + - name: Keep the bundles for the Fedora smoke test + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: linux-bundles + path: | + src-tauri/target/release/bundle/appimage/Moldavite_*_amd64.AppImage + src-tauri/target/release/bundle/rpm/Moldavite-*.x86_64.rpm + if-no-files-found: error + retention-days: 3 + + # The AppImage carries Ubuntu's GTK and WebKitGTK and borrows the graphics + # stack from whatever distribution runs it. Fedora's Mesa is newer than + # Ubuntu 24.04's, and that mix is what shipped a blank white window in 2.6.0 + # (#130): the WebKit web process aborted in EGL setup before the first + # paint, and nothing in CI could have noticed because the only Linux that + # ever ran the bundles was the Ubuntu that built them. The rpm uses Fedora's + # own WebKitGTK instead, and resolving its dependencies is part of the test. + # Each bundle has to launch under Xvfb on Fedora, keep its web process alive, + # and paint something other than a blank window. + smoke-linux-fedora: + name: smoke-linux-fedora + needs: build-linux + runs-on: ubuntu-24.04 + container: + image: fedora:44 + timeout-minutes: 20 + steps: + - name: Download the Linux bundles + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: linux-bundles + path: bundles + + - name: Install a headless desktop and the rpm + run: | + set -euo pipefail + dnf install -y --setopt=install_weak_deps=False \ + xorg-x11-server-Xvfb ImageMagick mesa-dri-drivers mesa-libEGL mesa-libGL \ + dbus-daemon dbus-tools xdg-utils desktop-file-utils procps-ng + rpm=$(find bundles -name 'Moldavite-*.x86_64.rpm' | head -n 1) + dnf install -y "$rpm" + # Extraction stands in for FUSE, which the container lacks. AppRun is + # what the AppImage runtime executes after mounting the same tree. + appimage=$(find bundles -name 'Moldavite_*_amd64.AppImage' | head -n 1) + chmod +x "$appimage" + (cd bundles && "$GITHUB_WORKSPACE/$appimage" --appimage-extract >/dev/null) + + - name: Launch each bundle under Xvfb + run: | + set -euo pipefail + smoke() { + local label=$1; shift + local log="$RUNNER_TEMP/$label.log" shot="$RUNNER_TEMP/$label.png" + Xvfb :99 -screen 0 1280x800x24 -nolisten tcp >/dev/null 2>&1 & + local xvfb=$! + sleep 2 + # setsid: the app, its WebKit processes and the session bus form + # one process group that can be torn down together afterwards. + DISPLAY=:99 setsid dbus-run-session -- "$@" >"$log" 2>&1 & + local app=$! + sleep 30 + local alive=1 web colors + kill -0 "$app" 2>/dev/null || alive=0 + web=$(pgrep -c -f WebKitWebProcess || true) + magick import -display :99 -window root "$shot" || true + colors=$(magick identify -format '%k' "$shot" 2>/dev/null || echo 0) + kill -TERM -- -"$app" 2>/dev/null || true + sleep 2 + kill -KILL -- -"$app" 2>/dev/null || true + pkill -KILL -f WebKitWebProcess || true + kill "$xvfb" 2>/dev/null || true + wait "$xvfb" 2>/dev/null || true + echo "== $label: alive=$alive web-processes=$web distinct-colors=$colors" + cat "$log" + local failed=0 + if grep -q 'Could not create default EGL display' "$log"; then + echo "::error::$label aborted in EGL setup, the #130 blank window"; failed=1 + fi + [ "$alive" = 1 ] || { echo "::error::$label exited during startup"; failed=1; } + [ "$web" -gt 0 ] || { echo "::error::$label has no WebKit web process"; failed=1; } + # A mapped but unpainted window is two colors: its white and the + # black root. Any rendered text pushes this into the hundreds. + [ "$colors" -gt 32 ] || { echo "::error::$label painted a blank window ($colors colors)"; failed=1; } + return $failed + } + status=0 + smoke appimage "$GITHUB_WORKSPACE/bundles/squashfs-root/AppRun" || status=1 + smoke rpm /usr/bin/moldavite || status=1 + exit $status + + - name: Keep the screenshots and logs + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: linux-smoke + path: | + ${{ runner.temp }}/*.png + ${{ runner.temp }}/*.log + if-no-files-found: warn + retention-days: 3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53e72d0c..7a5db2ad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,9 +74,10 @@ jobs: `3. Windows may show SmartScreen warning - click "More info" → "Run anyway"`, ``, `### Linux (beta)`, - `1. Download \`Moldavite_${process.env.PACKAGE_VERSION}_amd64.AppImage\` (any distribution) or \`Moldavite_${process.env.PACKAGE_VERSION}_amd64.deb\` (Debian, Ubuntu)`, + `1. Download \`Moldavite_${process.env.PACKAGE_VERSION}_amd64.AppImage\` (any distribution), \`Moldavite_${process.env.PACKAGE_VERSION}_amd64.deb\` (Debian, Ubuntu) or \`Moldavite-${process.env.PACKAGE_VERSION}-1.x86_64.rpm\` (Fedora)`, `2. AppImage: mark it executable and run it. Needs glibc 2.38 or newer (Ubuntu 24.04, Debian 13, Fedora 39 or later) and \`libfuse2\` (\`sudo apt install libfuse2\` on Ubuntu)`, `3. deb: \`sudo apt install ./Moldavite_${process.env.PACKAGE_VERSION}_amd64.deb\``, + `4. rpm: \`sudo dnf install ./Moldavite-${process.env.PACKAGE_VERSION}-1.x86_64.rpm\``, ].join('\n'); const { data } = await github.rest.repos.createRelease({ owner: context.repo.owner, @@ -107,7 +108,7 @@ jobs: # 24.04: the ONNX Runtime binary fastembed downloads needs glibc 2.38, # which 22.04 lacks. The bundles therefore need 2.38 at runtime too. - platform: 'ubuntu-24.04' - args: '--bundles appimage deb' + args: '--bundles appimage deb rpm' runs-on: ${{ matrix.platform }} steps: @@ -243,8 +244,25 @@ jobs: patchelf # No code signing on Linux; the AppImage is updater-signed like every - # other platform. The deb has no in-app updater and is replaced by - # installing the next one. + # other platform. The deb and the rpm have no in-app updater and are + # replaced by installing the next one. + # Tauri fetches its own linuxdeploy, a July 2024 build, into ~/.cache/tauri + # and reuses whatever is there. That build still copies Ubuntu's + # libwayland-client into the AppImage, and Fedora's and Arch's Mesa need + # a symbol from a newer one, so the WebKit web process aborted with + # "Could not create default EGL display" and the window stayed white + # (#130). linuxdeploy excludes the library since November 2024; seed the + # cache with a release that has it, pinned by checksum. + - name: Use a linuxdeploy that leaves libwayland-client to the host + if: matrix.platform == 'ubuntu-24.04' + run: | + set -euo pipefail + mkdir -p ~/.cache/tauri + curl -fsSL -o ~/.cache/tauri/linuxdeploy-x86_64.AppImage \ + https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20251107-1/linuxdeploy-x86_64.AppImage + echo "c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d $HOME/.cache/tauri/linuxdeploy-x86_64.AppImage" | sha256sum -c + chmod +x ~/.cache/tauri/linuxdeploy-x86_64.AppImage + - name: Build Linux app if: matrix.platform == 'ubuntu-24.04' uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0 @@ -436,6 +454,8 @@ jobs: `Moldavite_${version}_amd64.AppImage.sig`, `Moldavite_${version}_amd64.deb`, `Moldavite_${version}_amd64.deb.sig`, + `Moldavite-${version}-1.x86_64.rpm`, + `Moldavite-${version}-1.x86_64.rpm.sig`, `latest.json`, // The Chrome/Edge/Brave clipper, loaded unpacked. The Firefox XPI // is not here: it has to be signed through AMO by hand, and is @@ -518,11 +538,16 @@ jobs: asset: `Moldavite_${version}_amd64.AppImage`, signature: `Moldavite_${version}_amd64.AppImage.sig` }, - // The updater never installs a deb, but tauri-action signs it and - // lists it, so verify the signature it advertises like the rest. + // The updater never installs a deb or an rpm, but tauri-action + // signs and lists both, so verify the signatures it advertises + // like the rest. 'linux-x86_64-deb': { asset: `Moldavite_${version}_amd64.deb`, signature: `Moldavite_${version}_amd64.deb.sig` + }, + 'linux-x86_64-rpm': { + asset: `Moldavite-${version}-1.x86_64.rpm`, + signature: `Moldavite-${version}-1.x86_64.rpm.sig` } }; diff --git a/CHANGELOG.md b/CHANGELOG.md index 0531d9be..18e50dbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to Moldavite are documented here. ### Added +- **An rpm for Fedora.** Linux releases now ship `Moldavite-x.x.x-1.x86_64.rpm` next to the AppImage and the deb, installed with `sudo dnf install ./Moldavite-x.x.x-1.x86_64.rpm` and updated by installing the next one. + - **Start your synced Forge on Mac.** Turn on Use synced Forge in Settings → General to create a separate iCloud folder, write notes, or open it in Finder. Connect the same Forge on iPhone or iPad later using the same iCloud account. Your existing local Forges stay separate. - A reusable Moldavite brand kit and branded iPhone, iPad and App Store icons. @@ -18,6 +20,8 @@ All notable changes to Moldavite are documented here. ### Fixed +- **The Linux AppImage opened a blank white window on Fedora and Arch.** It carried Ubuntu's Wayland client library, and the newer Mesa on those distributions needs a symbol it lacks, so the WebKit web process aborted with "Could not create default EGL display: EGL_BAD_PARAMETER" before the first paint. The AppImage now leaves that library to the system, and every pull request launches the AppImage and the rpm on Fedora to prove they paint. (#130) + - An unpinned MCP client now reports that iCloud is unsupported when the synced Forge is active, instead of silently selecting the previous local Forge. Pin MCP clients to a local Forge with `--forge`. - iOS native controls and status-bar contrast follow the app theme. Long dialog diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f0a5e7fa..6664ac8c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ npm run format:check # Prettier check (cd src-tauri && cargo clippy --all-targets -- -D warnings) npm run build # Frontend production build npm run tauri build # Packaged app (DMG on macOS, EXE and MSI on Windows; - # add --bundles appimage deb on Linux) + # add --bundles appimage deb rpm on Linux) ``` Run the checks relevant to your change while iterating. Before requesting review, diff --git a/README.md b/README.md index 7a5a67b6..2f899395 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,13 @@ choose **More info → Run anyway**. Updates delivered inside the app are cryptographically signed and verified before they install. **Linux (beta)** — download `Moldavite_x.x.x_amd64.AppImage` for any -distribution, or `Moldavite_x.x.x_amd64.deb` for Debian and Ubuntu. Both need -glibc 2.38 or newer, which means Ubuntu 24.04, Debian 13, Fedora 39 or later; -the local semantic-search runtime sets that floor. Mark the AppImage executable -once, and install `libfuse2` if your distribution does not ship it -(`sudo apt install libfuse2` on Ubuntu). In-app updates work for the AppImage. -The deb is updated by installing the next one. +distribution, `Moldavite_x.x.x_amd64.deb` for Debian and Ubuntu, or +`Moldavite-x.x.x-1.x86_64.rpm` for Fedora. All need glibc 2.38 or newer, which +means Ubuntu 24.04, Debian 13, Fedora 39 or later; the local semantic-search +runtime sets that floor. Mark the AppImage executable once, and install +`libfuse2` if your distribution does not ship it (`sudo apt install libfuse2` +on Ubuntu). In-app updates work for the AppImage. The deb and the rpm are +updated by installing the next one. ## Connect your AI diff --git a/docs/PROJECT_STATUS.md b/docs/PROJECT_STATUS.md index 854dcf54..4a4027f2 100644 --- a/docs/PROJECT_STATUS.md +++ b/docs/PROJECT_STATUS.md @@ -59,7 +59,7 @@ This does not change the app's unreleased iOS status. - Windows is a beta release target. Every PR runs clippy and the Rust library test suite on `windows-latest`; no Windows runtime journey has been exercised manually, so Windows coverage is CI-backed and the platform stays beta until it is not -- Linux is a beta release target: an AppImage (any distribution, carries the updater) and a deb (Debian and Ubuntu, no in-app updater), built by the release workflow and proven by a `build-linux` job on every PR that asserts the exact artifact names the release verification requires. The crate has compiled and tested on `ubuntu-latest` since CI existed. No Linux runtime journey has been exercised by hand. Both bundles need glibc 2.38 or newer (Ubuntu 24.04, Debian 13, Fedora 39 or later) because the ONNX Runtime binary fastembed ships is built against it; the deb declares `libc6 (>= 2.38)` so apt refuses cleanly on older systems, and the AppImage needs `libfuse2` where the distribution does not ship it +- Linux is a beta release target: an AppImage (any distribution, carries the updater), a deb (Debian and Ubuntu) and an rpm (Fedora), the last two without an in-app updater, built by the release workflow and proven by a `build-linux` job on every PR that asserts the exact artifact names the release verification requires, then a `smoke-linux-fedora` job that launches the AppImage and the rpm under Xvfb in a Fedora container and fails on an EGL abort, a dead web process or a blank window (the 2.6.0 AppImage shipped exactly that on Fedora, #130). The crate has compiled and tested on `ubuntu-latest` since CI existed. No Linux runtime journey has been exercised by hand. All bundles need glibc 2.38 or newer (Ubuntu 24.04, Debian 13, Fedora 39 or later) because the ONNX Runtime binary fastembed ships is built against it; the deb declares `libc6 (>= 2.38)` so apt refuses cleanly on older systems, and the AppImage needs `libfuse2` where the distribution does not ship it - Calendar in right panel + timeline, read-only, from two sources: Apple (EventKit, permission-gated, macOS only) and Google (Calendar API v3 over PKCE loopback OAuth, all platforms, refresh token in the OS credential store). Per-source failures are reported without blanking the other source; Google needs `MOLDAVITE_GOOGLE_CLIENT_ID`/`_SECRET` at build time or it reports unavailable - macOS builds are signed and notarized. Windows installers are unsigned and may trigger SmartScreen because they are not Authenticode-signed. Linux bundles are unsigned as well; Linux has no equivalent warning. Updater artifacts are signed for every platform, including Windows, and clients verify them before installation. Checks run about 15 seconds after launch, every 24 hours while open, and on focus after 24 hours without a successful check, and can be switched off in Settings → About (manual checks still work); automatic network/404 failures stay silent and retry, while pending versions add accent dots to Settings and About plus the existing install action. Manual checks retain explicit errors, and completed upgrades show the CHANGELOG-backed "What's New" popup (see docs/RELEASING.md) - Themes/presets, platform-specific keyboard shortcut labels and overlay (⌘? on macOS, Ctrl+? on Windows and Linux), settings modal with focus trap diff --git a/docs/RELEASING.md b/docs/RELEASING.md index fa879bce..49fe6e70 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -1,7 +1,7 @@ # Releasing Moldavite Moldavite ships signed and notarized macOS builds (Apple Silicon and Intel) and -unsigned Windows and Linux builds (an AppImage and a deb) via GitHub Actions. Every platform's updater artifacts, +unsigned Windows and Linux builds (an AppImage, a deb and an rpm) via GitHub Actions. Every platform's updater artifacts, including Windows, are signed with `TAURI_SIGNING_PRIVATE_KEY` so the updater can verify their integrity. Windows installers are not Authenticode-signed, so Windows may show a SmartScreen warning, and Linux bundles are unsigned as well. This is the @@ -44,9 +44,9 @@ end-to-end release process. 3. The tag push triggers `.github/workflows/release.yml`, which: - creates the GitHub Release **as a draft**, with a body extracted from the `CHANGELOG.md` section for this version, - - builds macOS aarch64 + x86_64, Windows installers, and a Linux AppImage and - deb, signs and notarizes the macOS builds, and signs updater artifacts for - every platform, + - builds macOS aarch64 + x86_64, Windows installers, and a Linux AppImage, + deb and rpm, signs and notarizes the macOS builds, and signs updater + artifacts for every platform, - uploads artifacts and generates `latest.json` (the updater manifest), - **publishes the draft only once every artifact and signature is present**, and triggers the Homebrew bump after that. The release used to be created @@ -85,8 +85,8 @@ users see no `.xpi` on that release. ## 3. Verify -- Confirm the Release has the DMGs, the `.exe`/`.msi`, the `.AppImage` and - `.deb` with their `.sig` files, `latest.json`, and `moldavite-clipper-chrome.zip`. +- Confirm the Release has the DMGs, the `.exe`/`.msi`, the `.AppImage`, `.deb` + and `.rpm` with their `.sig` files, `latest.json`, and `moldavite-clipper-chrome.zip`. - Open an older install → it should detect the update after about 15s (or via Settings → About → Check for Updates), download, install, and relaunch. - On relaunch, the "What's New" popup shows this version's notes. diff --git a/docs/guide.html b/docs/guide.html index ec038a4a..c22fe265 100644 --- a/docs/guide.html +++ b/docs/guide.html @@ -143,12 +143,13 @@

Linux (beta)

Open the latest release - and download Moldavite_x.x.x_amd64.AppImage for any distribution, or - Moldavite_x.x.x_amd64.deb for Debian and Ubuntu. Both need glibc 2.38 or + and download Moldavite_x.x.x_amd64.AppImage for any distribution, + Moldavite_x.x.x_amd64.deb for Debian and Ubuntu, or + Moldavite-x.x.x-1.x86_64.rpm for Fedora. All need glibc 2.38 or newer, so Ubuntu 24.04, Debian 13, Fedora 39 or later; the local semantic-search runtime sets that floor. Mark the AppImage executable once, and install libfuse2 if your distribution does not ship it (sudo apt install libfuse2 on Ubuntu). In-app - updates work for the AppImage; the deb is + updates work for the AppImage; the deb and the rpm are updated by installing the next one. Linux builds pass the same test suite as macOS and Windows but have not yet been exercised by hand, which is why they are beta.

@@ -735,7 +736,7 @@

Claude Code

Run the generated command in a terminal. The examples below show a standard macOS app installation; on Windows and Linux, use the generated snippets so the path matches your - installer. A deb installs /usr/bin/moldavite; for an AppImage the path is the + installer. A deb or rpm installs /usr/bin/moldavite; for an AppImage the path is the .AppImage file itself, wherever you keep it.

claude mcp add moldavite -- "/Applications/Moldavite.app/Contents/MacOS/moldavite" --mcp
diff --git a/docs/index.html b/docs/index.html index 9c8ed3fc..b1fc8515 100644 --- a/docs/index.html +++ b/docs/index.html @@ -195,7 +195,7 @@

Clip a page in one click

Choose how you want to install.

Use Homebrew or a signed and notarized DMG on macOS, an x64 installer on Windows, or an - AppImage or deb on Linux. + AppImage, deb or rpm on Linux.

@@ -259,10 +259,10 @@

Run the EXE or MSI

Linux

-

AppImage or deb

+

AppImage, deb or rpm

- Open the latest release and download the AppImage for any distribution, or the deb - for Debian and Ubuntu. + Open the latest release and download the AppImage for any distribution, the deb + for Debian and Ubuntu, or the rpm for Fedora.

AppImage or deb

Linux is in beta and needs glibc 2.38 or newer (Ubuntu 24.04, Debian 13, Fedora 39 or later). Mark the AppImage executable once and install libfuse2 if - your distribution lacks it. In-app updates work for the AppImage, not the deb. + your distribution lacks it. In-app updates work for the AppImage, not the deb or + the rpm.

diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 58f2bf75..dc0ccced 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -114,6 +114,12 @@ "depends": [ "libc6 (>= 2.38)" ] + }, + "rpm": { + "depends": [ + "webkit2gtk4.1", + "gtk3" + ] } } }