diff --git a/pkgbuilds/vibecad-bin/.omarchy/package.json.in b/pkgbuilds/vibecad-bin/.omarchy/package.json.in new file mode 100644 index 00000000..bbe9ae19 --- /dev/null +++ b/pkgbuilds/vibecad-bin/.omarchy/package.json.in @@ -0,0 +1,5 @@ +{ + "source": "local", + "release_ring": "fast", + "min_release_age": "24h" +} diff --git a/pkgbuilds/vibecad-bin/.omarchy/upstream.sh b/pkgbuilds/vibecad-bin/.omarchy/upstream.sh new file mode 100755 index 00000000..ae47fbaa --- /dev/null +++ b/pkgbuilds/vibecad-bin/.omarchy/upstream.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# VibeCAD publishes a checksum file beside each AppImage. Read the small +# checksum asset instead of downloading the AppImage merely to +# discover whether a package update is available. +set -euo pipefail + +REPO='10-X-eng/vibecad' +RELEASES_URL="https://api.github.com/repos/${REPO}/releases?per_page=100" + +current=$(awk -F= '/^pkgver=/ { print $2; exit }' PKGBUILD) +package=$(awk -F= '/^pkgname=/ { print $2; exit }' PKGBUILD) +case "$package" in + vibecad-bin) preview=false ;; + vibecad-preview-bin) preview=true ;; + *) echo "Unsupported VibeCAD package: $package" >&2; exit 1 ;; +esac +releases=$(curl -fsSL "$RELEASES_URL") +jq -e 'type == "array"' <<<"$releases" >/dev/null +now=$(date +%s) +min_age=${MIN_RELEASE_AGE_SECONDS:-0} +best_version='' +best_tag='' +best_asset_url='' +best_checksum_url='' +best_published_at='' + +while IFS=$'\t' read -r tag published_at assets; do + [[ $tag =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-(alpha|beta|RC)([0-9]+))?-build([0-9]+)$ ]] || continue + + upstream_version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" + build="${BASH_REMATCH[5]}" + suffix="${BASH_REMATCH[3]}" + # Require both GitHub's classification and the tag to match the track. + # RCs never enter stable, even if a release is mislabeled on GitHub. + if [[ $preview == true ]]; then + [[ $suffix == RC ]] || continue + else + [[ -z $suffix ]] || continue + fi + version="${upstream_version/-RC/rc}" + version="${version/-beta/beta}" + version="${version/-alpha/alpha}.build${build}" + if [[ -z $published_at ]] || ! published_epoch=$(date --date="$published_at" +%s 2>/dev/null); then + echo "Release ${tag} has an invalid publication time" >&2 + exit 1 + fi + if (( now - published_epoch < min_age )) && [[ ${BYPASS_MIN_RELEASE_AGE:-} != 1 ]]; then + continue + fi + asset="VibeCAD-${upstream_version}-build${build}-Linux-x86_64.AppImage" + checksum="${asset}-SHA256.txt" + asset_url=$(jq -r --arg name "$asset" '.[] | select(.name == $name) | .browser_download_url' <<<"$assets") + checksum_url=$(jq -r --arg name "$checksum" '.[] | select(.name == $name) | .browser_download_url' <<<"$assets") + + [[ -n $asset_url && -n $checksum_url ]] || continue + expected_url="https://github.com/${REPO}/releases/download/${tag}/${asset}" + if [[ $asset_url != "$expected_url" || $checksum_url != "${expected_url}-SHA256.txt" ]]; then + echo "Unexpected asset URL for ${tag}" >&2 + exit 1 + fi + if [[ -z $best_version ]] || (( $(vercmp "$version" "$best_version") > 0 )); then + best_version=$version + best_tag=$tag + best_asset_url=$asset_url + best_checksum_url=$checksum_url + best_published_at=$published_at + fi +done < <(jq -r --argjson preview "$preview" '.[] | select(.draft == false and .prerelease == $preview) | [.tag_name, .published_at, (.assets | tojson)] | @tsv' <<<"$releases") + +if [[ -z $best_version ]]; then + echo "No eligible release for ${package}; package unchanged." >&2 + echo '{}' + exit 0 +fi + +if (( $(vercmp "$best_version" "$current") <= 0 )); then + echo '{}' + exit 0 +fi + +checksum_text=$(curl -fsSL "$best_checksum_url") +read -r sha256 checksum_name _ <<<"$checksum_text" +expected_name="${best_asset_url##*/}" +if [[ ! $sha256 =~ ^[0-9a-f]{64}$ ]] || [[ $checksum_name != "$expected_name" ]]; then + echo "Invalid checksum file for ${expected_name}" >&2 + exit 1 +fi + +license_sha256=$(curl -fsSL \ + "https://raw.githubusercontent.com/${REPO}/${best_tag}/LICENSE" | sha256sum | cut -d' ' -f1) +icon_sha256=$(curl -fsSL \ + "https://raw.githubusercontent.com/${REPO}/${best_tag}/docs/images/vibecad-mark.svg" | sha256sum | cut -d' ' -f1) + +jq -n \ + --arg pkgver "$best_version" \ + --arg published_at "$best_published_at" \ + --arg launcher "$(sha256sum vibecad | cut -d' ' -f1)" \ + --arg desktop "$(sha256sum vibecad.desktop | cut -d' ' -f1)" \ + --arg policy "$(sha256sum update-policy.json | cut -d' ' -f1)" \ + --arg license "$license_sha256" \ + --arg icon "$icon_sha256" \ + --arg sha256 "$sha256" \ + '{ + pkgver: $pkgver, + published_at: $published_at, + sha256sums: { + any: [$launcher, $desktop, $policy, $license, $icon], + x86_64: [$sha256] + } + }' diff --git a/pkgbuilds/vibecad-bin/PKGBUILD.in b/pkgbuilds/vibecad-bin/PKGBUILD.in new file mode 100644 index 00000000..0b6a029c --- /dev/null +++ b/pkgbuilds/vibecad-bin/PKGBUILD.in @@ -0,0 +1,63 @@ +# Maintainer: monomyth + +pkgname=vibecad-bin +pkgver=@STABLE_PKGVER@ +pkgrel=1 +pkgdesc="AI-native parametric CAD platform" +arch=('x86_64') +url="https://github.com/10-X-eng/vibecad" +license=('LGPL-2.1-or-later') + +depends=( + 'bash' + 'coreutils' + 'fuse2' + 'hicolor-icon-theme' + 'jq' + 'libdrm' +) + +provides=("vibecad=${pkgver}") +conflicts=('vibecad') +options=('!debug' '!strip') +backup=('etc/vibecad/update-policy.json') + +_upstream_version="${pkgver%.build*}" +_upstream_version="${_upstream_version/rc/-RC}" +_upstream_version="${_upstream_version/beta/-beta}" +_upstream_version="${_upstream_version/alpha/-alpha}" +_upstream_build="${pkgver##*.build}" +_tag="v${_upstream_version}-build${_upstream_build}" +_appimage="VibeCAD-${_upstream_version}-build${_upstream_build}-Linux-x86_64.AppImage" + +source=( + 'vibecad' + 'vibecad.desktop' + 'update-policy.json' + "LICENSE::https://raw.githubusercontent.com/10-X-eng/vibecad/${_tag}/LICENSE" + "vibecad.svg::https://raw.githubusercontent.com/10-X-eng/vibecad/${_tag}/docs/images/vibecad-mark.svg" +) +source_x86_64=("${_appimage}::https://github.com/10-X-eng/vibecad/releases/download/${_tag}/${_appimage}") +noextract=("${_appimage}") +sha256sums=( + '5dc3e8b5dcade0d54c1334533f318485179c62ab3866c4c22cc739af63aa58e5' + 'd31836d2aeaa48d113d7edf75572c57ce945de1867a78c07296d694fd87edebd' + 'bed3d14591ade955eceecaa0a27f8a196fcf0f32b7986ac758f9cec0e58809fa' + '@STABLE_LICENSE_SHA256@' + '@STABLE_ICON_SHA256@' +) +sha256sums_x86_64=('@STABLE_APPIMAGE_SHA256@') + +package() { + install -Dm755 "${srcdir}/${_appimage}" \ + "${pkgdir}/opt/vibecad/VibeCAD.AppImage" + install -Dm755 "${srcdir}/vibecad" "${pkgdir}/usr/bin/vibecad" + install -Dm644 "${srcdir}/vibecad.desktop" \ + "${pkgdir}/usr/share/applications/vibecad.desktop" + install -Dm644 "${srcdir}/vibecad.svg" \ + "${pkgdir}/usr/share/icons/hicolor/scalable/apps/vibecad.svg" + install -Dm644 "${srcdir}/update-policy.json" \ + "${pkgdir}/etc/vibecad/update-policy.json" + install -Dm644 "${srcdir}/LICENSE" \ + "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" +} diff --git a/pkgbuilds/vibecad-bin/README.md b/pkgbuilds/vibecad-bin/README.md new file mode 100644 index 00000000..9b717075 --- /dev/null +++ b/pkgbuilds/vibecad-bin/README.md @@ -0,0 +1,14 @@ +# VibeCAD stable package stub + +Inactive until upstream publishes a stable Linux release. `PKGBUILD.in` and `.omarchy/package.json.in` are templates, not registered package inputs; Omarchy's build and sync discovery skip this directory without `PKGBUILD`. + +The launcher contains the same automatic Hyprland/Qt scaling and AMD DRM fixes as `vibecad-preview-bin`. Keep `vibecad`, `update-policy.json`, and `.omarchy/upstream.sh` byte-identical between variants. The update hook selects stable releases for `pkgname=vibecad-bin` and rejects RC tags even if GitHub incorrectly labels them stable. + +To activate after a stable release exists: + +1. Verify the official GitHub release is not a draft or prerelease and has a version tag without an alpha, beta, or RC suffix. +2. Fill `@STABLE_PKGVER@` (for example, `26.3.1.build1`) and the three stable source checksum placeholders with the actual release metadata. Verify all local-source checksums too. +3. Rename `PKGBUILD.in` to `PKGBUILD` and `.omarchy/package.json.in` to `.omarchy/package.json`. +4. Confirm the launcher, policy, and update hook still match Preview. Build, test, and review the package before enabling its Omarchy menu entry. + +Do not substitute an RC for a missing stable release. Once published, this package follows normal Omarchy/pacman updates. It conflicts with the Preview variant through their shared `vibecad` provide; neither track silently switches to the other. diff --git a/pkgbuilds/vibecad-bin/update-policy.json b/pkgbuilds/vibecad-bin/update-policy.json new file mode 100644 index 00000000..8d9a3536 --- /dev/null +++ b/pkgbuilds/vibecad-bin/update-policy.json @@ -0,0 +1,4 @@ +{ + "enabled": false, + "automatic_checks": false +} diff --git a/pkgbuilds/vibecad-bin/vibecad b/pkgbuilds/vibecad-bin/vibecad new file mode 100644 index 00000000..3128a23f --- /dev/null +++ b/pkgbuilds/vibecad-bin/vibecad @@ -0,0 +1,33 @@ +#!/bin/bash + +# Upstream forces XCB, so Qt misses Hyprland's per-monitor scale. Use the +# focused monitor at launch, while respecting explicit Qt scaling overrides. +if [[ ! ${QT_SCALE_FACTOR+x} && ! ${QT_SCREEN_SCALE_FACTORS+x} && + ! ${QT_FONT_DPI+x} && ! ${QT_USE_PHYSICAL_DPI+x} && + ! ${QT_ENABLE_HIGHDPI_SCALING+x} && -n ${HYPRLAND_INSTANCE_SIGNATURE:-} ]] && + command -v hyprctl >/dev/null; then + scale=$(timeout 2s hyprctl -j monitors 2>/dev/null | jq -er ' + [.[] | select(.disabled != true)] + | (map(select(.focused == true))[0] // .[0]) + | .scale + | select(type == "number" and . >= 0.5 and . <= 8) + ' 2>/dev/null) + if [[ -n $scale ]]; then + export QT_SCALE_FACTOR="$scale" + fi +fi + +# VibeCAD's AppImage bundles libdrm_amdgpu from its build environment. On +# current Arch/Mesa systems that copy can make Qt's GLX probe see no usable +# framebuffer configurations. Preloading the host-matched library keeps the +# AppImage portable while preserving hardware acceleration. +for vendor_path in /sys/class/drm/card*/device/vendor; do + [ -r "$vendor_path" ] || continue + if [ "$(cat "$vendor_path")" = "0x1002" ] && [ -r /usr/lib/libdrm_amdgpu.so.1 ]; then + LD_PRELOAD="/usr/lib/libdrm_amdgpu.so.1${LD_PRELOAD:+:$LD_PRELOAD}" + export LD_PRELOAD + break + fi +done + +exec /opt/vibecad/VibeCAD.AppImage "$@" diff --git a/pkgbuilds/vibecad-bin/vibecad.desktop b/pkgbuilds/vibecad-bin/vibecad.desktop new file mode 100644 index 00000000..10e93258 --- /dev/null +++ b/pkgbuilds/vibecad-bin/vibecad.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Name=VibeCAD +Comment=Design editable 3D parts with AI-native parametric CAD +GenericName=CAD Application +Exec=vibecad --single-instance %F +Terminal=false +Type=Application +Icon=vibecad +Categories=Graphics;Engineering; +StartupNotify=true +StartupWMClass=VibeCAD +MimeType=application/x-extension-fcstd;model/obj;image/vnd.dwg;image/vnd.dxf;model/vnd.collada+xml;application/iges;model/iges;model/step;model/step+zip;model/stl;application/vnd.shp;model/vrml; diff --git a/pkgbuilds/vibecad-preview-bin/.omarchy/package.json b/pkgbuilds/vibecad-preview-bin/.omarchy/package.json new file mode 100644 index 00000000..bbe9ae19 --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/.omarchy/package.json @@ -0,0 +1,5 @@ +{ + "source": "local", + "release_ring": "fast", + "min_release_age": "24h" +} diff --git a/pkgbuilds/vibecad-preview-bin/.omarchy/test-upstream.py b/pkgbuilds/vibecad-preview-bin/.omarchy/test-upstream.py new file mode 100644 index 00000000..1fd2de36 --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/.omarchy/test-upstream.py @@ -0,0 +1,91 @@ +"""Offline release-track tests. Run with python3 on an Arch host (vercmp).""" + +import datetime +import json +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import unittest + +PACKAGE = Path(__file__).resolve().parents[1] + + +def release(tag, preview, *, draft=False, recent=False): + asset = f"VibeCAD-{tag[1:]}-Linux-x86_64.AppImage" + url = f"https://github.com/10-X-eng/vibecad/releases/download/{tag}/{asset}" + return { + "tag_name": tag, "prerelease": preview, "draft": draft, + "published_at": datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') + if recent else '2025-01-01T00:00:00Z', + "assets": [{"name": asset, "browser_download_url": url}, + {"name": asset + '-SHA256.txt', "browser_download_url": url + '-SHA256.txt'}], + } + + +class Tracks(unittest.TestCase): + def run_hook(self, package, releases, *, age=0, invalid_hash=False): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + for filename in ('vibecad', 'vibecad.desktop', 'update-policy.json'): + shutil.copy2(PACKAGE / filename, root / filename) + (root / 'PKGBUILD').write_text(f'pkgname={package}\npkgver=0\n') + stub = root / 'bin' + stub.mkdir() + curl = stub / 'curl' + curl.write_text('''#!/bin/bash +url="${@: -1}" +case "$url" in + *'/releases?per_page=100') printf '%s' "$RELEASE_FIXTURE" ;; + *'-SHA256.txt') name=${url##*/}; printf '%s %s\\n' "$TEST_HASH" "${name%-SHA256.txt}" ;; + *'/LICENSE') printf 'license' ;; + *'/vibecad-mark.svg') printf '' ;; + *) exit 99 ;; +esac +''') + curl.chmod(0o755) + env = dict(os.environ, PATH=f"{stub}:{os.environ['PATH']}", + RELEASE_FIXTURE=json.dumps(releases), TEST_HASH='bad' if invalid_hash else 'a' * 64, + MIN_RELEASE_AGE_SECONDS=str(age), BYPASS_MIN_RELEASE_AGE='') + return subprocess.run(['bash', str(PACKAGE / '.omarchy/upstream.sh')], + cwd=root, env=env, capture_output=True, text=True) + + def version(self, package, releases, **kwargs): + proc = self.run_hook(package, releases, **kwargs) + self.assertEqual(proc.returncode, 0, proc.stderr) + return json.loads(proc.stdout).get('pkgver') + + def test_stable_excludes_rc_even_when_mislabeled(self): + rows = [release('v26.3.1-build2', False), release('v27.0.0-RC1-build1', False), + release('v27.0.0-RC2-build1', True)] + self.assertEqual(self.version('vibecad-bin', rows), '26.3.1.build2') + + def test_preview_excludes_stable_drafts_and_other_prereleases(self): + rows = [release('v26.3.1-RC6-build1', True), release('v27.0.0-build1', False), + release('v27.0.0-RC1-build1', True, draft=True), release('v27.0.0-beta1-build1', True)] + self.assertEqual(self.version('vibecad-preview-bin', rows), '26.3.1rc6.build1') + + def test_rc_numbers_use_pacman_order(self): + rows = [release('v26.3.1-RC9-build1', True), release('v26.3.1-RC10-build1', True)] + self.assertEqual(self.version('vibecad-preview-bin', rows), '26.3.1rc10.build1') + + def test_no_stable_does_not_promote_rc(self): + self.assertIsNone(self.version('vibecad-bin', [release('v26.3.1-RC6-build1', True)])) + + def test_quarantine_selects_older_eligible_rc(self): + rows = [release('v26.3.1-RC7-build1', True, recent=True), release('v26.3.1-RC6-build1', True)] + self.assertEqual(self.version('vibecad-preview-bin', rows, age=86400), '26.3.1rc6.build1') + + def test_invalid_checksum_fails(self): + proc = self.run_hook('vibecad-preview-bin', [release('v26.3.1-RC6-build1', True)], invalid_hash=True) + self.assertNotEqual(proc.returncode, 0) + + def test_incorrect_asset_location_fails(self): + row = release('v26.3.1-RC6-build1', True) + row['assets'][0]['browser_download_url'] = 'https://example.org/wrong.AppImage' + self.assertNotEqual(self.run_hook('vibecad-preview-bin', [row]).returncode, 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/pkgbuilds/vibecad-preview-bin/.omarchy/upstream.sh b/pkgbuilds/vibecad-preview-bin/.omarchy/upstream.sh new file mode 100755 index 00000000..ae47fbaa --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/.omarchy/upstream.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# VibeCAD publishes a checksum file beside each AppImage. Read the small +# checksum asset instead of downloading the AppImage merely to +# discover whether a package update is available. +set -euo pipefail + +REPO='10-X-eng/vibecad' +RELEASES_URL="https://api.github.com/repos/${REPO}/releases?per_page=100" + +current=$(awk -F= '/^pkgver=/ { print $2; exit }' PKGBUILD) +package=$(awk -F= '/^pkgname=/ { print $2; exit }' PKGBUILD) +case "$package" in + vibecad-bin) preview=false ;; + vibecad-preview-bin) preview=true ;; + *) echo "Unsupported VibeCAD package: $package" >&2; exit 1 ;; +esac +releases=$(curl -fsSL "$RELEASES_URL") +jq -e 'type == "array"' <<<"$releases" >/dev/null +now=$(date +%s) +min_age=${MIN_RELEASE_AGE_SECONDS:-0} +best_version='' +best_tag='' +best_asset_url='' +best_checksum_url='' +best_published_at='' + +while IFS=$'\t' read -r tag published_at assets; do + [[ $tag =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-(alpha|beta|RC)([0-9]+))?-build([0-9]+)$ ]] || continue + + upstream_version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" + build="${BASH_REMATCH[5]}" + suffix="${BASH_REMATCH[3]}" + # Require both GitHub's classification and the tag to match the track. + # RCs never enter stable, even if a release is mislabeled on GitHub. + if [[ $preview == true ]]; then + [[ $suffix == RC ]] || continue + else + [[ -z $suffix ]] || continue + fi + version="${upstream_version/-RC/rc}" + version="${version/-beta/beta}" + version="${version/-alpha/alpha}.build${build}" + if [[ -z $published_at ]] || ! published_epoch=$(date --date="$published_at" +%s 2>/dev/null); then + echo "Release ${tag} has an invalid publication time" >&2 + exit 1 + fi + if (( now - published_epoch < min_age )) && [[ ${BYPASS_MIN_RELEASE_AGE:-} != 1 ]]; then + continue + fi + asset="VibeCAD-${upstream_version}-build${build}-Linux-x86_64.AppImage" + checksum="${asset}-SHA256.txt" + asset_url=$(jq -r --arg name "$asset" '.[] | select(.name == $name) | .browser_download_url' <<<"$assets") + checksum_url=$(jq -r --arg name "$checksum" '.[] | select(.name == $name) | .browser_download_url' <<<"$assets") + + [[ -n $asset_url && -n $checksum_url ]] || continue + expected_url="https://github.com/${REPO}/releases/download/${tag}/${asset}" + if [[ $asset_url != "$expected_url" || $checksum_url != "${expected_url}-SHA256.txt" ]]; then + echo "Unexpected asset URL for ${tag}" >&2 + exit 1 + fi + if [[ -z $best_version ]] || (( $(vercmp "$version" "$best_version") > 0 )); then + best_version=$version + best_tag=$tag + best_asset_url=$asset_url + best_checksum_url=$checksum_url + best_published_at=$published_at + fi +done < <(jq -r --argjson preview "$preview" '.[] | select(.draft == false and .prerelease == $preview) | [.tag_name, .published_at, (.assets | tojson)] | @tsv' <<<"$releases") + +if [[ -z $best_version ]]; then + echo "No eligible release for ${package}; package unchanged." >&2 + echo '{}' + exit 0 +fi + +if (( $(vercmp "$best_version" "$current") <= 0 )); then + echo '{}' + exit 0 +fi + +checksum_text=$(curl -fsSL "$best_checksum_url") +read -r sha256 checksum_name _ <<<"$checksum_text" +expected_name="${best_asset_url##*/}" +if [[ ! $sha256 =~ ^[0-9a-f]{64}$ ]] || [[ $checksum_name != "$expected_name" ]]; then + echo "Invalid checksum file for ${expected_name}" >&2 + exit 1 +fi + +license_sha256=$(curl -fsSL \ + "https://raw.githubusercontent.com/${REPO}/${best_tag}/LICENSE" | sha256sum | cut -d' ' -f1) +icon_sha256=$(curl -fsSL \ + "https://raw.githubusercontent.com/${REPO}/${best_tag}/docs/images/vibecad-mark.svg" | sha256sum | cut -d' ' -f1) + +jq -n \ + --arg pkgver "$best_version" \ + --arg published_at "$best_published_at" \ + --arg launcher "$(sha256sum vibecad | cut -d' ' -f1)" \ + --arg desktop "$(sha256sum vibecad.desktop | cut -d' ' -f1)" \ + --arg policy "$(sha256sum update-policy.json | cut -d' ' -f1)" \ + --arg license "$license_sha256" \ + --arg icon "$icon_sha256" \ + --arg sha256 "$sha256" \ + '{ + pkgver: $pkgver, + published_at: $published_at, + sha256sums: { + any: [$launcher, $desktop, $policy, $license, $icon], + x86_64: [$sha256] + } + }' diff --git a/pkgbuilds/vibecad-preview-bin/PKGBUILD b/pkgbuilds/vibecad-preview-bin/PKGBUILD new file mode 100644 index 00000000..c119b51b --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/PKGBUILD @@ -0,0 +1,63 @@ +# Maintainer: monomyth + +pkgname=vibecad-preview-bin +pkgver=26.3.1rc6.build1 +pkgrel=1 +pkgdesc="AI-native parametric CAD platform (release candidate)" +arch=('x86_64') +url="https://github.com/10-X-eng/vibecad" +license=('LGPL-2.1-or-later') + +depends=( + 'bash' + 'coreutils' + 'fuse2' + 'hicolor-icon-theme' + 'jq' + 'libdrm' +) + +provides=("vibecad=${pkgver}") +conflicts=('vibecad') +options=('!debug' '!strip') +backup=('etc/vibecad/update-policy.json') + +_upstream_version="${pkgver%.build*}" +_upstream_version="${_upstream_version/rc/-RC}" +_upstream_version="${_upstream_version/beta/-beta}" +_upstream_version="${_upstream_version/alpha/-alpha}" +_upstream_build="${pkgver##*.build}" +_tag="v${_upstream_version}-build${_upstream_build}" +_appimage="VibeCAD-${_upstream_version}-build${_upstream_build}-Linux-x86_64.AppImage" + +source=( + 'vibecad' + 'vibecad.desktop' + 'update-policy.json' + "LICENSE::https://raw.githubusercontent.com/10-X-eng/vibecad/${_tag}/LICENSE" + "vibecad.svg::https://raw.githubusercontent.com/10-X-eng/vibecad/${_tag}/docs/images/vibecad-mark.svg" +) +source_x86_64=("${_appimage}::https://github.com/10-X-eng/vibecad/releases/download/${_tag}/${_appimage}") +noextract=("${_appimage}") +sha256sums=( + '5dc3e8b5dcade0d54c1334533f318485179c62ab3866c4c22cc739af63aa58e5' + '495c9f737148982ae510f32b343569e2c8b99e1066bf7f83e0f6767ddc5974e7' + 'bed3d14591ade955eceecaa0a27f8a196fcf0f32b7986ac758f9cec0e58809fa' + '7ffe1954587c77dfba1cf8eb9b2ea743671fa6e63f9e7a2f258119d42e14eefe' + '01cd7fb7718e80891594d9a437bb0f61402dbf47f092c2237a19571fc72fa171' +) +sha256sums_x86_64=('2141fef939b90a45fdb5831daafbbe7e146cf7837c498904c1d0d700b01a16ed') + +package() { + install -Dm755 "${srcdir}/${_appimage}" \ + "${pkgdir}/opt/vibecad/VibeCAD.AppImage" + install -Dm755 "${srcdir}/vibecad" "${pkgdir}/usr/bin/vibecad" + install -Dm644 "${srcdir}/vibecad.desktop" \ + "${pkgdir}/usr/share/applications/vibecad.desktop" + install -Dm644 "${srcdir}/vibecad.svg" \ + "${pkgdir}/usr/share/icons/hicolor/scalable/apps/vibecad.svg" + install -Dm644 "${srcdir}/update-policy.json" \ + "${pkgdir}/etc/vibecad/update-policy.json" + install -Dm644 "${srcdir}/LICENSE" \ + "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" +} diff --git a/pkgbuilds/vibecad-preview-bin/README.md b/pkgbuilds/vibecad-preview-bin/README.md new file mode 100644 index 00000000..20e3ef05 --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/README.md @@ -0,0 +1,15 @@ +# VibeCAD Preview on Omarchy + +`vibecad-preview-bin` tracks published RC releases marked prerelease on GitHub. `vibecad-bin` is reserved for stable releases (not marked prerelease and with no prerelease suffix). As of 2026-09-04 upstream has published only RCs, so no stable binary package is included. Do not reclassify an RC as stable. + +An inactive stable recipe is kept in `../vibecad-bin/PKGBUILD.in`. When upstream publishes a stable release, activate that stub with its real version and verified checksums. Keep the launcher and update hook identical. The hook selects stable or preview based on `pkgname`. Both variants provide and conflict with `vibecad`, so switching variants replaces the installed package and retains user documents and preferences. Neither variant is installed as a dependency of the other. + +Launch VibeCAD from the application menu or run `vibecad`. The launcher reads the focused Hyprland monitor's scale because the upstream AppImage forces Qt's XCB backend. Fonts and icons retain their upstream defaults and scale together. No font preferences, theme files, window modes, or global display settings are changed by the package. + +Scaling is selected at startup. Restart VibeCAD after moving to a differently scaled monitor. Explicit Qt scaling environment variables take precedence. Outside a reachable Hyprland session, the launcher leaves Qt's scaling unchanged. + +Updates are managed by pacman; the supported VibeCAD update policy disables its in-app updater. On AMD hardware the launcher also preloads the host's `libdrm_amdgpu` to avoid a conflict with the bundled library. + +Once accepted and published by Omarchy, the existing six-hourly upstream-sync workflow proposes version/checksum updates. The package uses the standard 24-hour release quarantine and fast ring. After an update is reviewed, merged, built, and published, normal Omarchy updates or `sudo pacman -Syu` upgrade the installed variant. A locally installed package receives no new upstream builds until that repository publication exists. This package does not add an unattended updater or switch release tracks automatically. The Omarchy edge/rc/stable repository channels are separate from upstream VibeCAD's stable/preview classification: the explicit Preview package is opt-in on any supported channel. + +For installations that used the earlier Isengard experiments, user launchers and desktop overrides can shadow the packaged launcher. Retire those overrides after installing this package revision. The package deliberately does not modify files in users' home directories. diff --git a/pkgbuilds/vibecad-preview-bin/update-policy.json b/pkgbuilds/vibecad-preview-bin/update-policy.json new file mode 100644 index 00000000..8d9a3536 --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/update-policy.json @@ -0,0 +1,4 @@ +{ + "enabled": false, + "automatic_checks": false +} diff --git a/pkgbuilds/vibecad-preview-bin/vibecad b/pkgbuilds/vibecad-preview-bin/vibecad new file mode 100644 index 00000000..3128a23f --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/vibecad @@ -0,0 +1,33 @@ +#!/bin/bash + +# Upstream forces XCB, so Qt misses Hyprland's per-monitor scale. Use the +# focused monitor at launch, while respecting explicit Qt scaling overrides. +if [[ ! ${QT_SCALE_FACTOR+x} && ! ${QT_SCREEN_SCALE_FACTORS+x} && + ! ${QT_FONT_DPI+x} && ! ${QT_USE_PHYSICAL_DPI+x} && + ! ${QT_ENABLE_HIGHDPI_SCALING+x} && -n ${HYPRLAND_INSTANCE_SIGNATURE:-} ]] && + command -v hyprctl >/dev/null; then + scale=$(timeout 2s hyprctl -j monitors 2>/dev/null | jq -er ' + [.[] | select(.disabled != true)] + | (map(select(.focused == true))[0] // .[0]) + | .scale + | select(type == "number" and . >= 0.5 and . <= 8) + ' 2>/dev/null) + if [[ -n $scale ]]; then + export QT_SCALE_FACTOR="$scale" + fi +fi + +# VibeCAD's AppImage bundles libdrm_amdgpu from its build environment. On +# current Arch/Mesa systems that copy can make Qt's GLX probe see no usable +# framebuffer configurations. Preloading the host-matched library keeps the +# AppImage portable while preserving hardware acceleration. +for vendor_path in /sys/class/drm/card*/device/vendor; do + [ -r "$vendor_path" ] || continue + if [ "$(cat "$vendor_path")" = "0x1002" ] && [ -r /usr/lib/libdrm_amdgpu.so.1 ]; then + LD_PRELOAD="/usr/lib/libdrm_amdgpu.so.1${LD_PRELOAD:+:$LD_PRELOAD}" + export LD_PRELOAD + break + fi +done + +exec /opt/vibecad/VibeCAD.AppImage "$@" diff --git a/pkgbuilds/vibecad-preview-bin/vibecad.desktop b/pkgbuilds/vibecad-preview-bin/vibecad.desktop new file mode 100644 index 00000000..7b99186a --- /dev/null +++ b/pkgbuilds/vibecad-preview-bin/vibecad.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Name=VibeCAD Preview +Comment=Design editable 3D parts with AI-native parametric CAD +GenericName=CAD Application +Exec=vibecad --single-instance %F +Terminal=false +Type=Application +Icon=vibecad +Categories=Graphics;Engineering; +StartupNotify=true +StartupWMClass=VibeCAD +MimeType=application/x-extension-fcstd;model/obj;image/vnd.dwg;image/vnd.dxf;model/vnd.collada+xml;application/iges;model/iges;model/step;model/step+zip;model/stl;application/vnd.shp;model/vrml;