Merge pull request #149 from omacom-io/codex-desktop-upstream-feed

Track ChatGPT desktop from OpenAI's feed instead of the AUR
This commit is contained in:
David Heinemeier Hansson
2026-08-15 18:32:13 +02:00
committed by GitHub
12 changed files with 642 additions and 100 deletions
+95
View File
@@ -0,0 +1,95 @@
name: Sync Upstream Releases
on:
schedule:
# Every 6 hours, off the hour to dodge the scheduling backlog at :00
- cron: '20 */6 * * *'
workflow_dispatch:
inputs:
packages:
description: 'Specific packages to update (space-separated, leave empty for all)'
required: false
default: ''
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
# Runs in an Arch container for vercmp: whether a release is an upgrade has
# to be decided by the same comparator pacman will use on users' machines.
- name: Update packages from upstream release feeds
run: |
docker run --rm \
-e PACKAGES="$PACKAGES" \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
-v "$PWD/bin:/workspace/bin:ro" \
-v "$PWD/helpers:/workspace/helpers:ro" \
-v "$PWD/pkgbuilds:/workspace/pkgbuilds" \
-w /workspace \
archlinux:base-devel bash -lc '
set -euo pipefail
pacman -Syu --noconfirm jq
groupadd -g "$HOST_GID" runner
useradd -m -u "$HOST_UID" -g "$HOST_GID" runner
chown -R runner:runner /workspace/pkgbuilds
if [[ -n "${PACKAGES:-}" ]]; then
read -r -a package_args <<< "$PACKAGES"
runuser -u runner -- ./bin/sync-upstream "${package_args[@]}"
else
runuser -u runner -- ./bin/sync-upstream
fi
'
env:
PACKAGES: ${{ github.event.inputs.packages }}
- name: Check for changes
id: changes
run: |
if [ -z "$(git status --porcelain)" ]; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
else
echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi
- name: Create Pull Request
if: steps.changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: 'chore: sync upstream releases'
title: 'chore: sync upstream releases'
body: |
Automated update of packages that track an upstream vendor release
feed rather than the AUR.
Each package reports its newest release through
`.omarchy/upstream.sh`.
branch: auto/sync-upstream
delete-branch: true
labels: automated
reviewers: ryanrhughes
- name: Notify Basecamp on failure
if: failure() && env.BASECAMP_CHATBOT_URL != ''
env:
BASECAMP_CHATBOT_URL: ${{ secrets.BASECAMP_CHATBOT_URL }}
run: |
curl -s -o /dev/null \
-H "Content-Type: application/json" \
-d "$(jq -n --arg content \
"🔴 <strong>Upstream sync failed</strong><br><a href=\"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\">View run</a>" \
'{content: $content}')" \
"$BASECAMP_CHATBOT_URL"
+40 -2
View File
@@ -15,6 +15,7 @@ The filesystem no longer encodes release policy. Instead:
- all other packages reach `stable` by promoting tested edge artifacts with `bin/repo migrate`
- AUR sync behavior is controlled by `source`, `sync`, `aur`, patches, and hooks in `.omarchy/`
- packages can opt out of unscoped builds with `skip_build`; explicit `--package` builds remain available
- packages that follow a vendor release feed instead of the AUR carry an `.omarchy/upstream.sh` hook
## Prerequisites
### aarch64 Builds (Optional)
@@ -248,6 +249,40 @@ bin/sync-aur yay v4l2-relayd # Sync specific packages
AUR sync is metadata-driven. It preserves `.omarchy/`, replaces the package root with AUR contents, applies `.omarchy/patches/*.patch`, runs `.omarchy/post-sync.sh` when present, applies pkgrel metadata, removes AUR-only `.SRCINFO` and `.gitignore` files, and records `upstream_commit`.
### Sync Upstream Releases
```bash
bin/sync-upstream # Update every package with an upstream hook
bin/sync-upstream openai-codex-desktop # Update specific packages
```
Some vendors publish a release feed of their own that is faster and more precise
than the AUR packaging of it. Those packages are `source: local` — Omarchy owns
the PKGBUILD — and provide `.omarchy/upstream.sh`, a hook that reports the newest
upstream release as JSON on stdout:
```json
{
"pkgver": "1.2.3",
"sha256sums": { "x86_64": ["<sha256>"], "aarch64": ["<sha256>"] }
}
```
Architecture keys become `sha256sums_<arch>` in the PKGBUILD; the key `any` means
the unsuffixed `sha256sums` array, and only the arrays a hook names are touched.
An empty object (`{}`) reports no update, which is how a hook waits out a release
that has landed for one architecture but not yet the other.
When the reported version is newer than the checked-in one, `bin/sync-upstream`
rewrites `pkgver` and those checksum arrays and resets `pkgrel` to 1. A version
that is equal or older leaves the package alone, so a vendor rolling a release
back cannot walk the repository backwards.
Hooks should read checksums from whatever manifest the vendor publishes rather
than downloading the artifacts — see `pkgbuilds/openai-codex-desktop/.omarchy/upstream.sh`,
which reads OpenAI's Debian package index and never fetches the 750 MB of debs
it describes.
### Other
```bash
@@ -260,6 +295,7 @@ bin/repo push # Upload local builds to the host and publi
bin/add-package <package> # Add an AUR/local package with metadata
bin/package-worktree <package> # Create upstream/patched/current scratch workspace
bin/repo remove <package> # Remove package
bin/sync-upstream # Update packages that track a vendor release feed
bin/clean-docker # Clear Docker images/cache (forces fresh rebuild)
```
@@ -345,7 +381,8 @@ omarchy-pkgs/
│ └── .omarchy/
│ ├── package.json # Source/sync/release metadata
│ ├── patches/ # Omarchy patches reapplied after AUR sync
│ └── post-sync.sh # Optional dynamic post-sync customization hook
│ ├── post-sync.sh # Optional dynamic post-sync customization hook
│ └── upstream.sh # Optional vendor release feed hook (non-AUR packages)
├── build/
├── build-output/ # Unsigned packages (temporary)
│ ├── edge/
@@ -396,7 +433,7 @@ Minimal examples:
Fields:
- `source`: `aur` or `local`
- `source`: `aur` or `local`. A `local` package can still follow an upstream release with an `.omarchy/upstream.sh` hook.
- `sync`: optional for AUR packages; defaults to `true`. Set `false` for AUR-origin packages that Omarchy maintains manually.
- `aur`: optional AUR package name when it differs from the local package directory, usually for split packages.
- `release_ring`: optional. `fast` means the package is built directly for stable as well as edge. Packages without a ring build in edge and reach stable through tested artifact promotion (`bin/repo migrate`).
@@ -539,6 +576,7 @@ The repository includes GitHub workflows and systemd services for automated rele
#### GitHub Workflows
1. **sync-aur.yml** (Every 6 hours): Syncs AUR packages according to `.omarchy/package.json` and opens a PR when changes are found.
2. **sync-upstream.yml** (Every 6 hours): Runs `.omarchy/upstream.sh` for packages that track a vendor release feed and opens a PR when a newer version is out.
#### Systemd Services
+390
View File
@@ -0,0 +1,390 @@
#!/bin/bash
set -euo pipefail
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
source "$BUILD_ROOT/helpers/paths.sh"
source "$BUILD_ROOT/helpers/package-metadata.sh"
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT
SPECIFIC_PACKAGES=()
usage() {
cat <<EOF
Usage: $0 [PACKAGE...]
Update packages that track an upstream vendor release feed instead of the AUR.
A package opts in by providing pkgbuilds/<package>/.omarchy/upstream.sh, a hook
that reports the newest upstream release as JSON on stdout:
{
"pkgver": "1.2.3",
"sha256sums": { "x86_64": ["<sha256>"], "aarch64": ["<sha256>"] }
}
Architecture keys become sha256sums_<arch> in the PKGBUILD; the key "any" means
the unsuffixed sha256sums array. An empty object ({}) reports no update.
When the reported version is newer than the checked-in one, pkgver and the
listed checksum arrays are rewritten and pkgrel is reset to 1.
Arguments:
PACKAGE One or more package names to update (optional)
Examples:
$0 # Update every package with an upstream hook
$0 openai-codex-desktop # Update specific packages
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--*)
print_error "Unknown option: $1"
exit 1
;;
*)
SPECIFIC_PACKAGES+=("$1")
shift
;;
esac
done
if ! command -v vercmp >/dev/null 2>&1; then
print_error "vercmp not found: this needs pacman to decide whether a release is an upgrade"
exit 1
fi
print_header "Upstream Package Sync"
UPDATED=0
SKIPPED=0
FAILED=0
SPECIFIC_MODE=false
get_pkgver() {
local package_dir="$1"
grep -m1 '^pkgver=' "$package_dir/PKGBUILD" | cut -d= -f2- | tr -d "\"'"
}
assert_single_assignment() {
local pkgbuild="$1"
local pattern="$2"
local label="$3"
if [[ $(grep -c "$pattern" "$pkgbuild") -ne 1 ]]; then
print_error "Expected exactly one $label assignment in $pkgbuild"
return 1
fi
}
set_pkgbuild_scalar() {
local pkgbuild="$1"
local field="$2"
local value="$3"
assert_single_assignment "$pkgbuild" "^${field}=" "$field" || return 1
sed -i "s/^${field}=.*/${field}=${value}/" "$pkgbuild"
}
# Replace an array assignment, however many lines the original spans.
set_pkgbuild_array() {
local pkgbuild="$1"
local name="$2"
shift 2
local values=("$@")
assert_single_assignment "$pkgbuild" "^${name}=(" "$name" || return 1
if [[ ${#values[@]} -eq 0 ]]; then
print_error "No values to write for ${name}"
return 1
fi
local block="$TEMP_DIR/array-block"
if [[ ${#values[@]} -eq 1 ]]; then
printf "%s=('%s')\n" "$name" "${values[0]}" > "$block" || return 1
else
{
printf '%s=(\n' "$name"
printf " '%s'\n" "${values[@]}"
printf ')\n'
} > "$block" || return 1
fi
local rewritten="$TEMP_DIR/pkgbuild-rewritten"
if ! awk -v prefix="${name}=(" -v block="$block" '
!replaced && index($0, prefix) == 1 {
while ((getline line < block) > 0) print line
close(block)
replaced = 1
# A ")" anywhere past the opening closes the array; testing for one at end
# of line instead would treat a trailing comment as a continuation and eat
# every line up to the next ")".
if (index(substr($0, length(prefix) + 1), ")") == 0) skipping = 1
next
}
skipping { if ($0 ~ /\)/) skipping = 0; next }
{ print }
' "$pkgbuild" > "$rewritten"; then
print_error "Failed to rewrite ${name} in $pkgbuild"
rm -f "$rewritten"
return 1
fi
mv "$rewritten" "$pkgbuild"
}
# pacman's own comparator, because nothing else agrees with it at the corners:
# sort -V calls 1.0a newer than 1.0, vercmp calls it older, and pacman is what
# decides whether a published package is an upgrade.
version_is_newer() {
local candidate="$1"
local current="$2"
[[ "$candidate" != "$current" ]] || return 1
[[ "$(vercmp "$candidate" "$current")" -gt 0 ]]
}
validate_release() {
local release="$1"
# pkgver is written into the PKGBUILD, which makepkg sources as shell, so it
# is held to pacman's own character set rather than merely being non-empty.
# The anchors are \A and \z, not ^ and $: jq's $ also matches before a
# trailing newline, which would let "1.0\n" through and break the rewrite.
jq -e '
(.pkgver | type == "string" and test("\\A[A-Za-z0-9._+]+\\z"))
and (.sha256sums | type == "object" and length > 0)
and (.sha256sums | to_entries | all(
.key | test("\\A[a-z0-9_]+\\z")
))
and (.sha256sums | to_entries | all(
.value | type == "array" and length > 0 and all(test("\\A[0-9a-f]{64}\\z"))
))
' <<<"$release" >/dev/null
}
# Confirm the rewritten PKGBUILD parses and actually holds what we meant to put
# in it. Editing shell with awk and sed can go wrong in ways no amount of
# pattern-matching anticipates -- an array element carrying a ")" in a comment,
# say -- so the result is checked rather than trusted.
verify_pkgbuild() {
local pkgbuild="$1"
local release="$2"
local pkgver="$3"
shift 3
local arrays=("$@")
if ! bash -n "$pkgbuild" 2>/dev/null; then
print_error "Rewritten PKGBUILD is not valid shell"
return 1
fi
local dump
if ! dump=$(CARCH=x86_64 bash -c '
source "$1" >/dev/null 2>&1 || exit 1
printf "pkgver\t%s\n" "$pkgver"
printf "pkgrel\t%s\n" "$pkgrel"
for name in "${@:2}"; do
declare -n array="$name"
printf "%s\t%s\n" "$name" "${array[*]}"
done
' _ "$pkgbuild" "${arrays[@]}" 2>/dev/null); then
print_error "Rewritten PKGBUILD could not be read back"
return 1
fi
local expected
expected=$(
printf 'pkgver\t%s\n' "$pkgver"
printf 'pkgrel\t1\n'
local array arch
for array in "${arrays[@]}"; do
arch="${array#sha256sums}"
arch="${arch#_}"
[[ -n "$arch" ]] || arch="any"
printf '%s\t%s\n' "$array" \
"$(jq -r --arg arch "$arch" '.sha256sums[$arch] | join(" ")' <<<"$release")"
done
)
if [[ "$dump" != "$expected" ]]; then
print_error "Rewritten PKGBUILD does not hold the reported release"
diff <(echo "$expected") <(echo "$dump") | sed 's/^/ /' >&2 || true
return 1
fi
}
apply_release() {
local package_dir="$1"
local release="$2"
local pkgver="$3"
local pkgbuild="$package_dir/PKGBUILD"
local arch array values
local arrays=()
while IFS= read -r arch; do
if [[ "$arch" == "any" ]]; then
array="sha256sums"
else
array="sha256sums_$arch"
fi
arrays+=("$array")
done < <(jq -r '.sha256sums | keys[]' <<<"$release")
# validate_release guarantees at least one entry, so an empty list here means
# jq died inside the process substitution rather than that there is nothing
# to do.
if [[ ${#arrays[@]} -eq 0 ]]; then
print_error "Could not read the checksum architectures from the reported release"
return 1
fi
# Every edit lands on a scratch copy that replaces the PKGBUILD in one rename
# at the end, so a failure part way through leaves the original untouched
# rather than half updated.
local scratch="$pkgbuild.sync-upstream"
cp "$pkgbuild" "$scratch" || return 1
if ! (
assert_single_assignment "$scratch" '^pkgver=' pkgver || exit 1
assert_single_assignment "$scratch" '^pkgrel=' pkgrel || exit 1
for array in "${arrays[@]}"; do
arch="${array#sha256sums}"
arch="${arch#_}"
[[ -n "$arch" ]] || arch="any"
mapfile -t values < <(jq -r --arg arch "$arch" '.sha256sums[$arch][]' <<<"$release")
set_pkgbuild_array "$scratch" "$array" "${values[@]}" || exit 1
done
set_pkgbuild_scalar "$scratch" pkgver "$pkgver" || exit 1
set_pkgbuild_scalar "$scratch" pkgrel 1 || exit 1
verify_pkgbuild "$scratch" "$release" "$pkgver" "${arrays[@]}" || exit 1
); then
rm -f "$scratch"
return 1
fi
chmod --reference="$pkgbuild" "$scratch"
mv "$scratch" "$pkgbuild"
}
sync_package() {
local package="$1"
local package_dir="$PKGBUILDS_DIR/$package"
local hook="$package_dir/.omarchy/upstream.sh"
if [[ ! -f "$package_dir/PKGBUILD" ]]; then
print_error "Package $package has no PKGBUILD"
((++FAILED))
return 0
fi
if [[ ! -f "$hook" ]]; then
if [[ "$SPECIFIC_MODE" == true ]]; then
print_error "Package $package is missing .omarchy/upstream.sh"
((++FAILED))
else
print_info "Skipping $package: no upstream hook"
((++SKIPPED))
fi
return 0
fi
print_info "Checking $package for upstream releases..."
local release
if ! release=$(cd "$package_dir" && PACKAGE_NAME="$package" bash .omarchy/upstream.sh); then
print_error "Upstream hook failed for $package"
((++FAILED))
return 0
fi
if ! jq -e . >/dev/null 2>&1 <<<"$release"; then
print_error "Upstream hook for $package did not report valid JSON"
((++FAILED))
return 0
fi
if [[ "$(jq -r 'has("pkgver")' <<<"$release")" == "false" ]]; then
print_info " No upstream update reported"
((++SKIPPED))
return 0
fi
if ! validate_release "$release"; then
print_error "Upstream hook for $package reported a malformed release"
((++FAILED))
return 0
fi
local pkgver current_pkgver
pkgver=$(jq -r '.pkgver' <<<"$release")
current_pkgver=$(get_pkgver "$package_dir")
if [[ -z "$current_pkgver" ]]; then
print_error "Could not read pkgver from $package_dir/PKGBUILD"
((++FAILED))
return 0
fi
if [[ "$pkgver" == "$current_pkgver" ]]; then
print_info " Already at $current_pkgver"
((++SKIPPED))
return 0
fi
if ! version_is_newer "$pkgver" "$current_pkgver"; then
print_warning " Upstream reports $pkgver, older than the checked-in $current_pkgver; leaving it alone"
((++SKIPPED))
return 0
fi
if ! apply_release "$package_dir" "$release" "$pkgver"; then
print_error "Failed to update $package"
((++FAILED))
return 0
fi
print_success " $current_pkgver -> $pkgver"
((++UPDATED))
}
if [[ ${#SPECIFIC_PACKAGES[@]} -gt 0 ]]; then
SPECIFIC_MODE=true
for package in "${SPECIFIC_PACKAGES[@]}"; do
sync_package "$package"
done
else
while IFS= read -r package; do
sync_package "$package"
done < <(packages_for_upstream_sync)
fi
echo ""
if [[ $FAILED -gt 0 ]]; then
print_error "Upstream sync completed with failures"
else
print_success "Upstream sync complete!"
fi
echo " Target: $PKGBUILDS_DIR"
echo " Updated: $UPDATED"
echo " Skipped: $SKIPPED"
echo " Failed: $FAILED"
if [[ $FAILED -gt 0 ]]; then
exit 1
fi
+13
View File
@@ -135,6 +135,19 @@ packages_for_aur_sync() {
done
}
package_has_upstream_hook() {
local pkgdir="$1"
[[ -f "$pkgdir/.omarchy/upstream.sh" ]]
}
packages_for_upstream_sync() {
package_dirs | while IFS= read -r pkgdir; do
if package_has_upstream_hook "$pkgdir"; then
basename "$pkgdir"
fi
done
}
packages_for_mirror() {
local mirror="$1"
@@ -1,5 +1,4 @@
{
"source": "aur",
"release_ring": "fast",
"upstream_commit": "05f12e3c51ce07efb996698d4fae94327f45f03b"
"source": "local",
"release_ring": "fast"
}
@@ -1,15 +0,0 @@
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -55,6 +55,12 @@
conflicts=('chatgpt')
options=('!debug' '!strip')
+# Omarchy: the build image compresses with zstd at its default level, which
+# leaves this 1.3 GB Electron tree at 447 MB. Maximum zstd takes it to 322 MB
+# for ~4 extra minutes of build time -- worth it for a package this large that
+# every user re-downloads on each of OpenAI's frequent releases.
+COMPRESSZST=(zstd -c -z -q --ultra -22 --threads=0 -)
+
_deb_x86_64="chatgpt_${pkgver}_amd64.deb"
_deb_aarch64="chatgpt_${pkgver}_arm64.deb"
source=('chatgpt-launcher.sh')
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
# OpenAI ships the ChatGPT desktop app from its own Debian repository. The
# per-architecture package index carries both the version and the SHA256 of
# every deb, so an update costs two small HTTP requests instead of a 750 MB
# download, and the pool keeps old versions, so the URLs pinned in the PKGBUILD
# stay resolvable after the next release.
set -euo pipefail
BASE_URL="https://persistent.oaistatic.com/codex-app-prod/linux/deb"
declare -A DEB_ARCHES=([x86_64]=amd64 [aarch64]=arm64)
# Print "<version> <sha256>" for the newest stanza in a Packages index. Newest
# is vercmp's opinion, which is the one bin/sync-upstream and pacman both use;
# sort -V disagrees with it over versions like 1.0a.
newest_release() {
local index="$1"
local version sha256 best_version="" best_sha256=""
while read -r version sha256; do
if [[ -z "$best_version" ]] || [[ "$(vercmp "$version" "$best_version")" -gt 0 ]]; then
best_version="$version"
best_sha256="$sha256"
fi
done < <(awk '
{ sub(/\r$/, "") }
/^Version:/ { version = $2 }
/^SHA256:/ { sha256 = $2 }
/^$/ { if (version && sha256) print version, sha256; version = sha256 = "" }
END { if (version && sha256) print version, sha256 }
' <<<"$index")
[[ -n "$best_version" ]] || return 1
echo "$best_version $best_sha256"
}
versions=()
declare -A checksums=()
for arch in "${!DEB_ARCHES[@]}"; do
index=$(curl -fsSL "$BASE_URL/dists/stable/main/binary-${DEB_ARCHES[$arch]}/Packages")
read -r version sha256 <<<"$(newest_release "$index")"
if [[ -z "${version:-}" || -z "${sha256:-}" ]]; then
echo "No usable release found for $arch in the upstream package index" >&2
exit 1
fi
versions+=("$version")
checksums[$arch]="$sha256"
done
# A release lands one architecture at a time, and a single pkgver has to cover
# both. Report no update until they agree; the next run picks it up.
for version in "${versions[@]}"; do
if [[ "$version" != "${versions[0]}" ]]; then
echo "Upstream architectures are mid-release (${versions[*]}); skipping" >&2
echo '{}'
exit 0
fi
done
jq -n \
--arg pkgver "${versions[0]}" \
--arg x86_64 "${checksums[x86_64]}" \
--arg aarch64 "${checksums[aarch64]}" \
'{pkgver: $pkgver, sha256sums: {x86_64: [$x86_64], aarch64: [$aarch64]}}'
-12
View File
@@ -1,12 +0,0 @@
Copyright Arch Linux Contributors
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -1 +0,0 @@
../LICENSE
+13 -14
View File
@@ -1,10 +1,12 @@
# Maintainer: Parsiad Azimzadeh <parsiad.azimzadeh at gmail dot com>
# Maintainer: mothran
# Official downloads: https://chatgpt.com/codex/
# Maintainer: David Heinemeier Hansson <david@hey.com>
# Omarchy tracks OpenAI's own Debian repository rather than the AUR, which lags
# behind releases that ship several times a week. .omarchy/upstream.sh rewrites
# the version and checksums below from that repository's package index.
pkgname=openai-codex-desktop
pkgver=26.803.81509
pkgrel=8.1
pkgver=26.810.52044
pkgrel=1
pkgdesc="Official ChatGPT desktop app with Codex"
arch=('x86_64' 'aarch64')
url="https://chatgpt.com/codex/"
@@ -64,16 +66,13 @@ COMPRESSZST=(zstd -c -z -q --ultra -22 --threads=0 -)
_deb_x86_64="chatgpt_${pkgver}_amd64.deb"
_deb_aarch64="chatgpt_${pkgver}_arm64.deb"
source=('chatgpt-launcher.sh')
source_x86_64=(
"${_deb_x86_64}::https://persistent.oaistatic.com/codex-app-prod/linux/deb/latest/chatgpt_amd64.deb"
)
source_aarch64=(
"${_deb_aarch64}::https://persistent.oaistatic.com/codex-app-prod/linux/deb/latest/chatgpt_arm64.deb"
)
_pool="https://persistent.oaistatic.com/codex-app-prod/linux/deb/pool/main/c/chatgpt"
source_x86_64=("${_deb_x86_64}::${_pool}/${_deb_x86_64}")
source_aarch64=("${_deb_aarch64}::${_pool}/${_deb_aarch64}")
noextract=("${_deb_x86_64}" "${_deb_aarch64}")
sha256sums=('4e3ca9302600bed268f8fd3ba2c9ac2f1ceb99da139ed71c50db0289b118d06f')
sha256sums_x86_64=('a9bf91a368f9f7c4eea38082a9fb8fb46b8d005b719a6d7715d2e5a1982c38eb')
sha256sums_aarch64=('f38fcc194eca9ab0327dc10c92340681eae77c5d75164df700384ce2adaccbc1')
sha256sums=('b3a4503b5931f102444bc7015c3cf4e40266cf034e0d682bd2a407dc5b3ee58c')
sha256sums_x86_64=('708a15a1bb76e2bb7f0e376e5145391fa277ad3a64057c1d32537bdc2a1b4e6e')
sha256sums_aarch64=('6ebea681b1e494d218a199f638b4bc886e94e1458dd61079b1e390a6fb98fdd2')
package() {
cd "${srcdir}"
-25
View File
@@ -1,25 +0,0 @@
version = 1
[[annotations]]
path = [
"PKGBUILD",
"README.md",
"keys/**",
".SRCINFO",
".gitignore",
".nvchecker.toml",
"*.install",
"*.sysusers",
"*sysusers.conf",
"*.tmpfiles",
"*tmpfiles.conf",
"*.logrotate",
"*.pam",
"*.service",
"*.socket",
"*.timer",
"*.desktop",
"*.hook",
]
SPDX-FileCopyrightText = "Arch Linux contributors"
SPDX-License-Identifier = "0BSD"
+23 -28
View File
@@ -1,37 +1,32 @@
#!/bin/bash
# SPDX-FileCopyrightText: 2026 Arch Linux Contributors
# SPDX-License-Identifier: 0BSD
set -euo pipefail
user_flags=()
ozone_flags=()
config_home="${XDG_CONFIG_HOME:-}"
if [[ -z "${config_home}" && -n "${HOME:-}" ]]; then
config_home="${HOME}/.config"
[[ -n "$config_home" || -z "${HOME:-}" ]] || config_home="$HOME/.config"
flags_file="${config_home:+$config_home/codex-flags.conf}"
if [[ -n "$flags_file" && -f "$flags_file" && -r "$flags_file" ]]; then
while IFS= read -r line || [[ -n "$line" ]]; do
line="${line%%#*}"
[[ -n "${line//[[:space:]]/}" ]] || continue
read -r -a flags <<<"$line"
user_flags+=("${flags[@]}")
done <"$flags_file"
fi
if [[ -n "${config_home}" && -f "${config_home}/codex-flags.conf" ]]; then
while IFS= read -r flag_line || [[ -n "${flag_line}" ]]; do
flag_line="${flag_line%%#*}"
read -r -a flag_parts <<<"${flag_line}"
user_flags+=("${flag_parts[@]}")
done <"${config_home}/codex-flags.conf"
# Chromium's own Ozone detection falls back to XWayland often enough to matter,
# and the result is a blurry window on every scaled display. Ask for Wayland
# directly, unless the user has already picked a platform themselves.
platform_flags=()
if [[ -n "${WAYLAND_DISPLAY:-}" || "${XDG_SESSION_TYPE:-}" == wayland ]]; then
platform_flags=(--ozone-platform=wayland)
for flag in "${user_flags[@]}" "$@"; do
case "$flag" in
--ozone-platform=* | --ozone-platform-hint=*) platform_flags=() ;;
esac
done
fi
# Use native Wayland rendering in Wayland sessions. Chromium's automatic Ozone
# selection can fall back to XWayland, which produces a blurry UI on scaled
# displays. An explicit platform argument from the user always takes precedence.
if [[ "${XDG_SESSION_TYPE:-}" == wayland || -n "${WAYLAND_DISPLAY:-}" ]]; then
ozone_flags=(--ozone-platform=wayland)
fi
# A platform selected in the flags file or on the command line overrides the
# native Wayland default.
for flag in "${user_flags[@]}" "$@"; do
case "${flag}" in
--ozone-platform=*|--ozone-platform-hint=*) ozone_flags=() ;;
esac
done
exec /usr/lib/chatgpt/ChatGPT "${ozone_flags[@]}" "${user_flags[@]}" "$@"
exec /usr/lib/chatgpt/ChatGPT "${platform_flags[@]}" "${user_flags[@]}" "$@"