Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apps/maple-research/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ just desktop-dev # Tauri desktop and native features
pinned ONNX Runtime and applies a local Tauri configuration overlay when one is
present.

For a separately installed macOS package targeting the standalone Auth Dev site,
use the [Research Dev desktop package](docs/research-dev-desktop.md). It has its
For a separately installed desktop package targeting the standalone Auth Dev site,
use the [Research Dev desktop package](docs/research-dev-desktop.md), built with
`nix run --no-update-lock-file .#research-dev-desktop` on Linux or macOS. It has its
own bundle identity, callback scheme, storage, and disabled updater; the ordinary
Local workflow and iOS Dev TestFlight profile remain separate.

Expand Down
61 changes: 58 additions & 3 deletions apps/maple-research/docs/research-dev-desktop.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Research Dev desktop package

This manual macOS package rehearses Research's native OAuth handoff through the
standalone Auth Dev site. It is separate from the ordinary `just desktop-dev`
Local workflow and from the existing iOS Dev TestFlight build.
These manual macOS and Linux packages use hosted Dev and rehearse Research's
native OAuth handoff through the standalone Auth Dev site. They install beside
production Maple. They are separate from the ordinary `just desktop-dev` Local
workflow and from the existing iOS Dev TestFlight build.

## Fixed profile

Expand All @@ -26,6 +27,60 @@ profile are unchanged.

## Build locally

Run this from the repository root on Linux or macOS (with pinned Xcode on macOS):

```bash
nix run --no-update-lock-file .#research-dev-desktop
```

Nix supplies the pinned build tools; the script selects the fixed hosted Dev
profile. Stop running frontend development servers first: this script reinstalls
frontend dependencies and rebuilds `dist`. It does not change `.env.local` or
publish, upload, sign, or install the result. A Dev account is required; a
production account is not automatically available on hosted Dev.

### Fedora / Linux RPM

The Linux build produces an unsigned host-architecture RPM:

```text
apps/maple-research/frontend/src-tauri/target/research-dev/maple-research-dev-<version>-1.<arch>.rpm
apps/maple-research/frontend/src-tauri/target/research-dev/build-profile.json
```

Install the exact RPM printed at the end of the build, for example on x86_64:

```bash
sudo dnf install ./apps/maple-research/frontend/src-tauri/target/research-dev/maple-research-dev-<version>-1.x86_64.rpm
```

Replace `<version>` with the built version. DNF installs WebKitGTK automatically.
The Dev profile declares its own `libwebkit2gtk-4.1.so.0()(64bit)` RPM capability;
it does not inherit or require a change to the production RPM dependency policy.
This capability is provided by Fedora's `webkit2gtk4.1` and openSUSE's
`libwebkit2gtk-4_1-0` packages. Package metadata compatibility is not a substitute
for install-and-launch validation on each target distribution.
Launch **Maple Research Dev** from KDE's application launcher or run
`maple-research-dev`. Production keeps the `maple` RPM and command; Dev uses
`maple-research-dev` for the package, command, desktop entry, icon, and private
ONNX Runtime directory. Config/data and single-instance routing use the separate
`cloud.opensecret.maple.dev` app ID. The script verifies the final RPM's package
name, dependencies, ELF metadata, callback registration, and isolated file paths.

The intermediate DEB is not a supported install artifact. Linux build files live
under `target/research-dev/cargo` rather than replacing ordinary desktop outputs.
Only this explicit local command builds the Dev RPM; existing PR/release package
jobs and production identities are unchanged.

Older `ci-desktop-pr` RPMs use Dev services but retain the production `maple`
package identity. They do **not** install beside production. Restore the website
RPM to that slot separately; for equal versions use `sudo dnf reinstall ./<rpm>`,
or `sudo dnf downgrade ./<rpm>` if the website version is older. Sign in again if
needed; do not copy credentials between the two apps. No automatic data migration
or deletion is performed by the Dev build.

### macOS

From the repository root on macOS, with the pinned Xcode installed:

```bash
Expand Down
11 changes: 7 additions & 4 deletions apps/maple-research/frontend/src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ fn validate_desktop_dev_profile() {
std::env::var("VITE_MAPLE_DESKTOP_VARIANT").is_err(),
"use the Research Dev desktop build script"
);
if target_os == "macos" {
if matches!(target_os.as_str(), "macos" | "linux") {
assert_ne!(
config["identifier"], "cloud.opensecret.maple.dev",
"use the Research Dev desktop build script for this bundle"
);
}
return;
}
assert_eq!(
target_os, "macos",
"Research Dev desktop packaging currently supports macOS"
assert!(
matches!(target_os.as_str(), "macos" | "linux"),
"Research Dev desktop packaging supports macOS and Linux"
);
let profile: serde_json::Value =
serde_json::from_str(include_str!("desktop-dev-profile.json")).unwrap();
Expand All @@ -72,6 +72,9 @@ fn validate_desktop_dev_profile() {
serde_json::json!([])
);
assert_eq!(config["bundle"]["createUpdaterArtifacts"], false);
if target_os == "linux" {
assert_eq!(config["mainBinaryName"], profile["linux"]["packageName"]);
}
}

#[allow(dead_code)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
"identifier": "cloud.opensecret.maple.dev",
"productName": "Maple Research Dev",
"scheme": "cloud.opensecret.maple.dev",
"linux": {
"packageName": "maple-research-dev",
"runtimeDependencies": ["libwebkit2gtk-4.1.so.0()(64bit)"]
},
"environment": {
"MAPLE_DESKTOP_VARIANT": "dev",
"VITE_MAPLE_DESKTOP_VARIANT": "dev",
Expand Down
10 changes: 9 additions & 1 deletion apps/maple-research/frontend/src-tauri/src/onnxruntime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@ fn runtime_library_path() -> PathBuf {
if let Some(directory) = executable.parent() {
#[cfg(target_os = "linux")]
{
let bundled = directory.join("../lib/maple/libonnxruntime.so");
let library_directory = if option_env!("MAPLE_DESKTOP_VARIANT") == Some("dev") {
"maple-research-dev"
} else {
"maple"
};
let bundled = directory
.join("../lib")
.join(library_directory)
.join("libonnxruntime.so");
if bundled.exists() {
return bundled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"main"
],
"platforms": [
"macOS"
"macOS",
"linux"
],
"permissions": [
"core:default",
Expand Down
9 changes: 9 additions & 0 deletions docs/repository-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ Research Linux packaging builds AppImage and DEB with Tauri, then the RPM from
the normalized DEB payload. `scripts/ci/sccache-stats.sh` reports compiler-cache
statistics with the build's own cache configuration.

For a side-by-side hosted Dev installation, use
`nix run --no-update-lock-file .#research-dev-desktop`, not an ordinary Research
PR package. The Linux Dev command stages its own DEB payload and normalizes it
into the separately named `maple-research-dev` RPM under `target/research-dev`.
It uses the fixed Dev native identity and callback scheme, disables updates,
and verifies the final package contains only Dev-owned executable, launcher,
icon, and runtime paths. See the
[Research Dev package guide](../apps/maple-research/docs/research-dev-desktop.md).

## SDK consumption

Follow the [consumer version policy](sdk-publishing.md#consumer-version-policy).
Expand Down
12 changes: 12 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,18 @@
touch "$out"
'';
};
apps.research-dev-desktop = flake-utils.lib.mkApp {
drv = pkgs.writeShellApplication {
name = "maple-research-dev-desktop";
text = ''
if ! command -v nix >/dev/null 2>&1; then
echo "error: nix must be available on PATH" >&2
exit 127
fi
exec nix develop --no-update-lock-file ".#${if pkgs.stdenv.isLinux then "desktop-linux" else "ci"}" -c ./scripts/ci/research-dev-desktop.sh "$@"
'';
};
};
}
);
}
23 changes: 16 additions & 7 deletions scripts/ci/_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1876,7 +1876,9 @@ extract_appimage_tool() {
tmp="$(mktemp -d)"
rm -rf "${out}"

if ! unsquashfs -d "${tmp}/squashfs-root" -o "${offset}" "${appimage}" >/dev/null; then
# Host SELinux labels and other privileged attributes must not be restored
# from an AppImage during an unprivileged build.
if ! unsquashfs -xattrs-include '^user\.' -d "${tmp}/squashfs-root" -o "${offset}" "${appimage}" >/dev/null; then
rm -rf "${tmp}"
return 1
fi
Expand Down Expand Up @@ -3922,17 +3924,23 @@ rpm_arch() {
build_rpm_package_from_payload() {
local rpm="$1"
local payload="$2"
local config="${3:-${TAURI_DIR}/tauri.conf.json}"
local topdir spec built_rpm
local version release arch rpm_build_shell
local version release arch rpm_build_shell requires name summary

command -v rpmbuild >/dev/null 2>&1 || {
echo "rpmbuild is required to build RPM packages. Run through the flake CI shell." >&2
return 1
}
rpm_build_shell="$(command -v bash)"

version="$(jq -r '.version' "${TAURI_DIR}/tauri.conf.json")"
release="$(jq -r '.bundle.linux.rpm.release // "1"' "${TAURI_DIR}/tauri.conf.json")"
version="$(jq -r '.version' "${config}")"
release="$(jq -r '.bundle.linux.rpm.release // "1"' "${config}")"
name="$(jq -r '.mainBinaryName // "maple"' "${config}")"
summary="$(jq -r 'if .mainBinaryName then .productName else "Maple AI" end' "${config}")"
# The normalized RPM bypasses Tauri's bundler and automatic RPM requirements.
# Preserve the explicit runtime dependencies from the shared bundle config.
requires="$(jq -r '.bundle.linux.rpm.depends // [] | map("Requires: " + .) | join("\n")' "${config}")"
arch="$(rpm_arch)"
topdir="$(mktemp -d)"
spec="${topdir}/SPECS/maple.spec"
Expand All @@ -3941,17 +3949,18 @@ build_rpm_package_from_payload() {
mkdir -p "${topdir}/BUILD" "${topdir}/BUILDROOT" "${topdir}/RPMS" "${topdir}/SOURCES" "${topdir}/SPECS" "${topdir}/SRPMS" "${topdir}/tmp"

cat > "${spec}" <<EOF
Name: maple
Name: ${name}
Epoch: 0
Version: ${version}
Release: ${release}
Summary: Maple AI
Summary: ${summary}
License: MIT
BuildArch: ${arch}
AutoReqProv: no
${requires}

%description
Maple AI
${summary}

%prep

Expand Down
60 changes: 55 additions & 5 deletions scripts/ci/research-dev-desktop.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#!/usr/bin/env bash
# Manual, unsigned macOS host-architecture package. No upload or publication.
# Manual, unsigned host-architecture Dev package. No upload or publication.
set -euo pipefail
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
if [ "$(host_os)" != "darwin" ]; then
echo "Research Dev desktop packaging currently supports macOS." >&2
exit 1
fi
case "$(host_os)" in
linux | darwin) ;;
*)
echo "Research Dev desktop packaging supports macOS and Linux." >&2
exit 1
;;
esac
print_source_provenance
verify_rust_lockfile
install_frontend_deps
Expand All @@ -18,6 +21,53 @@ unset CARGO_TARGET_DIR MAPLE_IOS_VARIANT TAURI_CONFIG APPLE_SIGNING_IDENTITY TAU
configure_reproducible_build_metadata
remove_generated_ios_cargo_config
build_frontend_dist
if [ "$(host_os)" = "linux" ]; then
# Keep intermediate packages and executables out of the production build tree.
evidence_dir="${TAURI_DIR}/target/research-dev"
export CARGO_TARGET_DIR="${evidence_dir}/cargo"
mkdir -p "${evidence_dir}"
prepare_linux_onnxruntime
config="${evidence_dir}/tauri.linux.conf.json"
python3 "${SCRIPT_DIR}/research-dev-profile.py" linux-config --ort-library "${ORT_DYLIB_PATH}" > "${config}"
cd "${FRONTEND_DIR}"
# The DEB is only an intermediate payload. Distribute the normalized RPM below.
remove_build_tree "${CARGO_TARGET_DIR}/release/bundle/deb"
bun tauri build --bundles deb --no-sign --config "${config}"
debs=()
while IFS= read -r -d '' deb; do
debs+=("${deb}")
done < <(find "${CARGO_TARGET_DIR}/release/bundle/deb" -type f -name '*.deb' -print0)
if [ "${#debs[@]}" -ne 1 ]; then
echo "Research Dev packaging requires exactly one Debian payload source." >&2
exit 1
fi
name="$(jq -r '.mainBinaryName' "${config}")"
rpm="${evidence_dir}/${name}-$(jq -r '.version' "${config}")-1.$(rpm_arch).rpm"
payload="$(mktemp -d)"
trap 'rm -rf "${payload}"' EXIT
extract_deb_payload "${debs[0]}" "${payload}/staged"
sanitize_linux_package_executable "${payload}/staged/usr/bin/${name}"
python3 "${SCRIPT_DIR}/tauri_bundle_type.py" --expect deb --set rpm "${payload}/staged/usr/bin/${name}"
python3 "${SCRIPT_DIR}/research-dev-profile.py" stage-linux --bundle "${payload}/staged" > /dev/null
build_rpm_package_from_payload "${rpm}" "${payload}/staged" "${config}"
if [ "$(rpm -qp --queryformat '%{NAME}' "${rpm}")" != "${name}" ]; then
echo "Research Dev RPM has the wrong package name." >&2
exit 1
fi
mkdir "${payload}/installed"
# cpio may stop at the archive trailer before rpm2cpio finishes writing its
# padding. Avoid a timing-dependent SIGPIPE under pipefail.
rpm2cpio "${rpm}" > "${payload}/installed.cpio"
(cd "${payload}/installed" && cpio -id --quiet --no-absolute-filenames < "${payload}/installed.cpio")
# Do not use production's RPM verifier: its dependency policy is independent
# of the Dev profile. Verify this package's executable and requirements here.
verify_linux_package_executable_metadata "${payload}/installed/usr/bin/${name}"
python3 "${SCRIPT_DIR}/tauri_bundle_type.py" --expect rpm "${payload}/installed/usr/bin/${name}"
python3 "${SCRIPT_DIR}/research-dev-profile.py" verify-linux --bundle "${payload}/installed" --rpm "${rpm}" > "${evidence_dir}/build-profile.json"
verify_frontend_dist_unchanged
printf 'Verified Research Dev RPM: %s\nProfile evidence: %s\n' "${rpm}" "${evidence_dir}/build-profile.json"
exit 0
fi
use_xcode_toolchain
prepare_macos_onnxruntime
export MACOSX_DEPLOYMENT_TARGET="13.4"
Expand Down
Loading
Loading