From 4bacdbc8dd45529968e9c7efa4dd146982a396f3 Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 01:32:15 +0200 Subject: [PATCH 1/7] docs(mirror): upstream now ships an arm64 AppImage Co-Authored-By: Claude Opus 5 --- .github/workflows/mirror-linux-build.yml | 10 +++++----- MIRROR.md | 9 +++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/mirror-linux-build.yml b/.github/workflows/mirror-linux-build.yml index 0e580572beb1..4f2641f1dddc 100644 --- a/.github/workflows/mirror-linux-build.yml +++ b/.github/workflows/mirror-linux-build.yml @@ -1,14 +1,14 @@ name: Mirror Linux build # Builds .deb and .rpm for x64 and arm64 from an upstream tag and publishes -# them as a release on this fork. Upstream's own release workflow ships a Linux -# x64 AppImage only, so this fills in the distro packages upstream never builds +# them as a release on this fork. Upstream's own release workflow ships Linux +# only as an AppImage, so this fills in the distro packages upstream never builds # without touching any upstream file. The AppImage is left to upstream; the # auto-update patch makes these .deb/.rpm installs updatable in place from this # fork's releases. # -# Every step here mirrors the "Linux x64" matrix entry of upstream's -# .github/workflows/release.yml. When that entry gains a dependency, this +# Every step here mirrors the Linux matrix entries of upstream's +# .github/workflows/release.yml. When those gain a dependency, this # workflow needs the same one. See MIRROR.md. on: @@ -427,7 +427,7 @@ jobs: fi echo "---" echo - echo "These are **not** official T3 Code builds. They are produced by this fork from unmodified upstream source at [\`$TAG\`](https://github.com/pingdotgg/t3code/releases/tag/$TAG), because upstream CI ships a Linux x64 AppImage only. This tag is $channel_note." + echo "These are **not** official T3 Code builds. They are produced by this fork from unmodified upstream source at [\`$TAG\`](https://github.com/pingdotgg/t3code/releases/tag/$TAG), because upstream CI ships Linux only as an AppImage. This tag is $channel_note." echo echo "- Formats: \`.deb\` and \`.rpm\`, x64 and arm64" echo "- **Auto-update works**, from this fork's releases. Installs prompt once for your password (via \`pkexec\`) because the update is applied with \`dpkg\`/\`rpm\`, the same way Windows prompts through UAC. A desktop without \`pkexec\` cannot auto-update; reinstall the newer package by hand." diff --git a/MIRROR.md b/MIRROR.md index 5eac8e4bd185..07f3d92f73c0 100644 --- a/MIRROR.md +++ b/MIRROR.md @@ -2,7 +2,7 @@ This fork exists to build T3 Code Linux packages that upstream CI does not produce. -Upstream `pingdotgg/t3code` ships a Linux **x64 AppImage** and nothing else for Linux. This fork adds the distro packages upstream never builds: +Upstream `pingdotgg/t3code` ships Linux only as an **AppImage** (x64 and arm64), plus the AUR packages that repackage it. This fork adds the distro packages upstream never builds: - `.deb` and `.rpm` - x64 and arm64 @@ -35,7 +35,7 @@ You can also build a specific tag by hand: Actions → Mirror Linux build → Ru ## Keeping up with upstream -The build steps are copied from the "Linux x64" matrix entry in upstream's `.github/workflows/release.yml`. When upstream adds a build dependency, this fork needs it too. +The build steps are copied from the "Linux x64" and "Linux arm64" matrix entries in upstream's `.github/workflows/release.yml`. When upstream adds a build dependency, this fork needs it too. There is no drift-detection job, deliberately. Upstream's `preflightLinuxDesktopBuild` in `scripts/build-desktop-artifact.ts` already checks `LINUX_DESKTOP_BUILD_PREREQUISITES` and fails with the missing package names, so a new dependency shows up as a legible build error rather than something subtle. Read that error before assuming the workflow is at fault. @@ -72,9 +72,6 @@ Assignment needs a `MIRROR_COPILOT_TOKEN` repository secret holding a PAT with i ## Upstreaming -Two things here are worth offering upstream, and both are small: - -- The arm64 gap is about eight lines in their release matrix, on a free runner. -- The auto-update patch is three lines and benefits them the moment they ship any distro package. It is also arguably a bug fix: the current check asks "is this an AppImage" when what it means is "can this install be updated", and electron-updater already answers that question more precisely. +The auto-update patch is worth offering upstream. It is three lines and benefits them the moment they ship any distro package. It is also arguably a bug fix: the current check asks "is this an AppImage" when what it means is "can this install be updated", and electron-updater already answers that question more precisely. This fork is worth keeping for `.deb` and `.rpm` either way, since those carry real packaging support burden upstream has not signed up for. From 39c3a56f0eccfda2b8ce9d98845cfc6a8b919d98 Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 01:32:40 +0200 Subject: [PATCH 2/7] fix(mirror): refuse to publish an incomplete update feed Co-Authored-By: Claude Opus 5 --- .github/scripts/merge-linux-update-manifests.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/scripts/merge-linux-update-manifests.py b/.github/scripts/merge-linux-update-manifests.py index db4971e9247a..77219d74da26 100755 --- a/.github/scripts/merge-linux-update-manifests.py +++ b/.github/scripts/merge-linux-update-manifests.py @@ -23,6 +23,7 @@ # Order matters: the first present target supplies the legacy top-level # path/sha512 that pre-6.x clients fall back to when `files` is absent. TARGET_PRIORITY = ("deb", "rpm") +ARCH_FEED_SUFFIXES = ("-linux.yml", "-linux-arm64.yml") def main(argv: list[str]) -> int: @@ -50,6 +51,18 @@ def main(argv: list[str]) -> int: print(f"No manifests found in {manifest_dir}", file=sys.stderr) return 1 + # A half-populated feed is worse than none: clients trust it and the + # missing format silently never sees an update. + for suffix in ARCH_FEED_SUFFIXES: + if not any(feed.endswith(suffix) for feed in groups): + print(f"No *{suffix} feed; an architecture failed to build", file=sys.stderr) + return 1 + for feed, by_target in sorted(groups.items()): + absent = [t for t in TARGET_PRIORITY if t not in by_target] + if absent: + print(f"{feed}: missing {', '.join(absent)} manifest", file=sys.stderr) + return 1 + for feed, by_target in sorted(groups.items()): ordered = [t for t in TARGET_PRIORITY if t in by_target] ordered += [t for t in sorted(by_target) if t not in TARGET_PRIORITY] From 8ff33c139ecd51b4d3091f704aabdce084b475d3 Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 01:33:26 +0200 Subject: [PATCH 3/7] fix(mirror): mark package descriptions as an unofficial build Co-Authored-By: Claude Opus 5 --- .../0002-linux-deb-rpm-package-metadata.md | 4 +++- .../0002-linux-deb-rpm-package-metadata.patch | 12 ++++++------ mirror-patches/0003-linux-appstream-metainfo.patch | 2 +- .../0003-linux-appstream-metainfo.wslprebuild.patch | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mirror-patches/0002-linux-deb-rpm-package-metadata.md b/mirror-patches/0002-linux-deb-rpm-package-metadata.md index 156c8ab9c3eb..28e2cfe40536 100644 --- a/mirror-patches/0002-linux-deb-rpm-package-metadata.md +++ b/mirror-patches/0002-linux-deb-rpm-package-metadata.md @@ -14,7 +14,9 @@ there. `FpmTarget` reads `license` straight off that staged metadata for the rpm build-internal string `"T3 Code desktop build"`, and `LinuxTargetHelper.getDescription` feeds it to the deb `Description:` field, the rpm `%description`, and the `.desktop` `Comment` — so it surfaced verbatim - in `apt show` and as both title and subtitle in GNOME Software. + in `apt show` and as both title and subtitle in GNOME Software. It ends by + saying the build is unofficial, as does the AppStream description in 0003, + since both are what users see before installing. - `desktop.entry` additions (`GenericName`, `Keywords`). `Keywords` is a desktop-entry string list, so it keeps its trailing `;` — dropping it makes the whole value invalid. `Comment` is deliberately not set there: diff --git a/mirror-patches/0002-linux-deb-rpm-package-metadata.patch b/mirror-patches/0002-linux-deb-rpm-package-metadata.patch index 38c48624bbe1..e95cf8518e9a 100644 --- a/mirror-patches/0002-linux-deb-rpm-package-metadata.patch +++ b/mirror-patches/0002-linux-deb-rpm-package-metadata.patch @@ -1,8 +1,8 @@ diff --git a/scripts/build-desktop-artifact.ts b/scripts/build-desktop-artifact.ts -index 44d5f0ab1..ae8818c84 100644 +index cb47e40b8..b5a4060d5 100644 --- a/scripts/build-desktop-artifact.ts +++ b/scripts/build-desktop-artifact.ts -@@ -944,6 +944,8 @@ interface StagePackageJson { +@@ -930,6 +930,8 @@ interface StagePackageJson { readonly packageManager: string; readonly description: string; readonly author: string; @@ -11,18 +11,18 @@ index 44d5f0ab1..ae8818c84 100644 readonly main: string; readonly build: Record; readonly dependencies: Record; -@@ -2761,6 +2763,10 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( +@@ -2737,6 +2739,10 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( executableName: "t3code", icon: "icons", category: "Development", + maintainer: "T3 Tools <97451137+TonybynMp4@users.noreply.github.com>", + synopsis: "The open-source control plane for coding agents", + description: -+ "Orchestrate Claude Code, Codex, Antigravity, OpenCode, Cursor, and Grok from one surface. Bring your own subscriptions.", ++ "Orchestrate Claude Code, Codex, Antigravity, OpenCode, Cursor, and Grok from one surface. Bring your own subscriptions. Unofficial community build of T3 Code.", // electron-builder turns these into MimeType=x-scheme-handler/; // in the .desktop entry (Exec already gets %U), so browsers can hand // t3code:// OAuth callbacks to the app. -@@ -2773,9 +2779,15 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( +@@ -2749,9 +2755,15 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( desktop: { entry: { StartupWMClass: "t3code", @@ -38,7 +38,7 @@ index 44d5f0ab1..ae8818c84 100644 } if (platform === "win") { -@@ -3774,7 +3786,9 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( +@@ -3651,7 +3663,9 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( private: true, packageManager: rootPackageJson.packageManager, description: "T3 Code desktop build", diff --git a/mirror-patches/0003-linux-appstream-metainfo.patch b/mirror-patches/0003-linux-appstream-metainfo.patch index 3ad9608f8777..e2fad353f5ac 100644 --- a/mirror-patches/0003-linux-appstream-metainfo.patch +++ b/mirror-patches/0003-linux-appstream-metainfo.patch @@ -23,7 +23,7 @@ index 848c5806b..95e3f8deb 100644 + The open-source control plane for coding agents + +

-+ Orchestrate Claude Code, Codex, Antigravity, OpenCode, Cursor, and Grok from one surface. Bring your own subscriptions. ++ Orchestrate Claude Code, Codex, Antigravity, OpenCode, Cursor, and Grok from one surface. Bring your own subscriptions. This is an unofficial community build of T3 Code. +

+
+ diff --git a/mirror-patches/0003-linux-appstream-metainfo.wslprebuild.patch b/mirror-patches/0003-linux-appstream-metainfo.wslprebuild.patch index 143a3684141b..a02984b6151b 100644 --- a/mirror-patches/0003-linux-appstream-metainfo.wslprebuild.patch +++ b/mirror-patches/0003-linux-appstream-metainfo.wslprebuild.patch @@ -23,7 +23,7 @@ index 44d5f0ab1..7dc738f85 100644 + The open-source control plane for coding agents + +

-+ Orchestrate Claude Code, Codex, Antigravity, OpenCode, Cursor, and Grok from one surface. Bring your own subscriptions. ++ Orchestrate Claude Code, Codex, Antigravity, OpenCode, Cursor, and Grok from one surface. Bring your own subscriptions. This is an unofficial community build of T3 Code. +

+
+ From 954098bc8d1ba6829fe0d4470a1a301e2f97411d Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 01:34:10 +0200 Subject: [PATCH 4/7] feat(mirror): enable cloud sign-in and T3 Connect Co-Authored-By: Claude Opus 5 --- .github/workflows/mirror-linux-build.yml | 7 ++++++- MIRROR.md | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/mirror-linux-build.yml b/.github/workflows/mirror-linux-build.yml index 4f2641f1dddc..3976abd80d81 100644 --- a/.github/workflows/mirror-linux-build.yml +++ b/.github/workflows/mirror-linux-build.yml @@ -154,6 +154,12 @@ jobs: # keeps that intentional rather than incidental, and guarantees a build # run from a differently-named repo never points users at upstream. T3CODE_DESKTOP_UPDATE_REPOSITORY: ${{ github.repository }} + # Upstream's public T3 Connect config, as baked into its own release + # builds. Without it cloud sign-in and T3 Connect are compiled out. + T3CODE_CLERK_PUBLISHABLE_KEY: pk_live_Y2xlcmsudDMuY29kZXMk + T3CODE_CLERK_JWT_TEMPLATE: t3-relay + T3CODE_CLERK_CLI_OAUTH_CLIENT_ID: hzxSgY2cH10sDU2r + T3CODE_RELAY_URL: https://relay.t3.codes steps: - name: Checkout upstream tag uses: actions/checkout@v6 @@ -432,7 +438,6 @@ jobs: echo "- Formats: \`.deb\` and \`.rpm\`, x64 and arm64" echo "- **Auto-update works**, from this fork's releases. Installs prompt once for your password (via \`pkexec\`) because the update is applied with \`dpkg\`/\`rpm\`, the same way Windows prompts through UAC. A desktop without \`pkexec\` cannot auto-update; reinstall the newer package by hand." echo "- For the AppImage, use the official [pingdotgg/t3code releases](https://github.com/pingdotgg/t3code/releases) - this fork does not rebuild it." - echo "- Cloud sign-in and T3 Connect are disabled in these builds. See MIRROR.md." echo echo "For official builds, use [pingdotgg/t3code releases](https://github.com/pingdotgg/t3code/releases)." } > release-notes.md diff --git a/MIRROR.md b/MIRROR.md index 07f3d92f73c0..69ebe71eb211 100644 --- a/MIRROR.md +++ b/MIRROR.md @@ -7,19 +7,19 @@ Upstream `pingdotgg/t3code` ships Linux only as an **AppImage** (x64 and arm64), - `.deb` and `.rpm` - x64 and arm64 -The AppImage is left to upstream; use their releases for it. Nothing else differs, apart from a three-line patch that lets `.deb` and `.rpm` installs use the in-app updater (see below). Everything else is upstream's source at an upstream tag. +The AppImage is left to upstream; use their releases for it. The source is upstream's at an upstream tag, plus the small patches in `mirror-patches/` that make `.deb` and `.rpm` installs updatable and properly described (see below). ## What these builds are not They are not official. Nobody at T3 Tools signs off on them, and bugs you hit here should be reproduced against an official build before being reported upstream. -Two behavioural differences worth knowing before you install: +Two things worth knowing before you install: **Auto-update works, and it updates from this fork.** The in-app "Update available" flow works on both formats. `.deb` and `.rpm` prompt once for your password through `pkexec`, because applying the update means running `dpkg -i` or `rpm -U` as root - the same trade Windows makes with its UAC prompt. No apt or dnf repository to add, and no waiting for a scheduled `apt upgrade`. -These builds update from **this fork's** releases, not upstream's, since that is where the arm64 and distro packages live. Moving to an official build later means downloading it from upstream once. +These builds update from **this fork's** releases, not upstream's, since that is where the distro packages live. Moving to an official build later means downloading it from upstream once. -**No cloud sign-in or T3 Connect.** Those need `T3CODE_CLERK_PUBLISHABLE_KEY` and `T3CODE_RELAY_URL`, which upstream injects from its own production environment. This fork does not have them, so `apps/server/vite.config.ts` bakes in empty strings and the features stay off. Local and LAN use is unaffected. Setting these would point users at the maintainers' relay infrastructure, so don't, without asking them first. +**Cloud sign-in and T3 Connect work, against upstream's service.** The build bakes in the same public Clerk and relay config upstream's own release builds carry (`T3CODE_CLERK_*`, `T3CODE_RELAY_URL` in `mirror-linux-build.yml`), so these builds use the maintainers' relay infrastructure exactly like an official install. If upstream rotates any of those values, update them there. ## How it works From bfc4544900fab7141503949eb692d0314b487e26 Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 01:37:33 +0200 Subject: [PATCH 5/7] fix(mirror): declare the audio and GBM libraries Electron needs Co-Authored-By: Claude Opus 5 --- .../0002-linux-deb-rpm-package-metadata.md | 5 +++ .../0002-linux-deb-rpm-package-metadata.patch | 33 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/mirror-patches/0002-linux-deb-rpm-package-metadata.md b/mirror-patches/0002-linux-deb-rpm-package-metadata.md index 28e2cfe40536..1d2882a059ed 100644 --- a/mirror-patches/0002-linux-deb-rpm-package-metadata.md +++ b/mirror-patches/0002-linux-deb-rpm-package-metadata.md @@ -23,6 +23,11 @@ there. `FpmTarget` reads `license` straight off that staged metadata for the rpm `LinuxTargetHelper.writeDesktopEntry` merges `desktop.entry` first and then overwrites `Comment` from `description`, so an entry value would be silently dropped. +- `deb.depends` and `rpm.depends`: electron-builder's defaults plus the ALSA + and GBM libraries, which Electron links against but the defaults omit, so a + minimal install could not start the app. `depends` replaces the defaults, so + they are copied; the install job in `mirror-linux-build.yml` catches it with + `ldd` if the list falls behind again. - `deb.recommends` and `deb.packageCategory`. `recommends` includes `policykit-1 | pkexec` because electron-updater installs a downloaded `.deb` through `pkexec`. It also repeats electron-builder's own default diff --git a/mirror-patches/0002-linux-deb-rpm-package-metadata.patch b/mirror-patches/0002-linux-deb-rpm-package-metadata.patch index e95cf8518e9a..a2a45f758efa 100644 --- a/mirror-patches/0002-linux-deb-rpm-package-metadata.patch +++ b/mirror-patches/0002-linux-deb-rpm-package-metadata.patch @@ -1,5 +1,5 @@ diff --git a/scripts/build-desktop-artifact.ts b/scripts/build-desktop-artifact.ts -index cb47e40b8..b5a4060d5 100644 +index cb47e40b8..17e513520 100644 --- a/scripts/build-desktop-artifact.ts +++ b/scripts/build-desktop-artifact.ts @@ -930,6 +930,8 @@ interface StagePackageJson { @@ -22,7 +22,7 @@ index cb47e40b8..b5a4060d5 100644 // electron-builder turns these into MimeType=x-scheme-handler/; // in the .desktop entry (Exec already gets %U), so browsers can hand // t3code:// OAuth callbacks to the app. -@@ -2749,9 +2755,15 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( +@@ -2749,9 +2755,42 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( desktop: { entry: { StartupWMClass: "t3code", @@ -32,13 +32,40 @@ index cb47e40b8..b5a4060d5 100644 }, }; + buildConfig.deb = { ++ depends: [ ++ "libgtk-3-0", ++ "libnotify4", ++ "libnss3", ++ "libxss1", ++ "libxtst6", ++ "xdg-utils", ++ "libatspi2.0-0", ++ "libuuid1", ++ "libsecret-1-0", ++ "libasound2", ++ "libgbm1", ++ ], + recommends: ["libappindicator3-1", "policykit-1 | pkexec"], + packageCategory: "devel", ++ }; ++ buildConfig.rpm = { ++ depends: [ ++ "gtk3", ++ "libnotify", ++ "nss", ++ "libXScrnSaver", ++ "(libXtst or libXtst6)", ++ "xdg-utils", ++ "at-spi2-core", ++ "(libuuid or libuuid1)", ++ "(alsa-lib or libasound2)", ++ "(mesa-libgbm or libgbm1)", ++ ], + }; } if (platform === "win") { -@@ -3651,7 +3663,9 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( +@@ -3651,7 +3690,9 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( private: true, packageManager: rootPackageJson.packageManager, description: "T3 Code desktop build", From 7337e3eec778e8c772b8656aadb2b62f5518a397 Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 01:37:33 +0200 Subject: [PATCH 6/7] ci(mirror): install each package in a clean distro before publishing Co-Authored-By: Claude Opus 5 --- .github/workflows/mirror-linux-build.yml | 58 +++++++++++++++++++++++- MIRROR.md | 2 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mirror-linux-build.yml b/.github/workflows/mirror-linux-build.yml index 3976abd80d81..375fb188bf53 100644 --- a/.github/workflows/mirror-linux-build.yml +++ b/.github/workflows/mirror-linux-build.yml @@ -332,9 +332,65 @@ jobs: path: release-publish/** if-no-files-found: error + # Installs each package into a clean distro image, so a missing dependency, + # a package of the wrong format, or a build without the updater marker fails + # here instead of on a user's machine. + install: + name: Install ${{ matrix.target }} ${{ matrix.arch }} + needs: [build] + runs-on: ${{ matrix.runner }} + container: ${{ matrix.image }} + timeout-minutes: 15 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - { target: deb, arch: x64, runner: ubuntu-26.04, image: "debian:13" } + - { target: deb, arch: arm64, runner: ubuntu-26.04-arm, image: "debian:13" } + - { target: rpm, arch: x64, runner: ubuntu-26.04, image: "fedora:43" } + - { target: rpm, arch: arm64, runner: ubuntu-26.04-arm, image: "fedora:43" } + steps: + - name: Download package + uses: actions/download-artifact@v8 + with: + name: linux-${{ inputs.tag }}-${{ matrix.target }}-${{ matrix.arch }} + path: package + + - name: Install and inspect + shell: bash + env: + TARGET: ${{ matrix.target }} + run: | + set -euo pipefail + packages=(package/*."$TARGET") + if [[ "${#packages[@]}" -ne 1 ]]; then + echo "Expected one .$TARGET, found: ${packages[*]}" >&2 + exit 1 + fi + if [[ "$TARGET" == deb ]]; then + apt-get update + apt-get install -y "./${packages[0]}" + files=$(dpkg -L t3code) + else + dnf install -y "./${packages[0]}" + files=$(rpm -ql t3code) + fi + binary=$(grep '^/opt/.*/t3code$' <<<"$files") + dir=$(dirname "$binary") + if [[ "$(cat "$dir/resources/package-type")" != "$TARGET" ]]; then + echo "resources/package-type is not $TARGET; in-app updates would be disabled." >&2 + exit 1 + fi + if ldd "$binary" | grep 'not found'; then + echo "Package dependencies do not cover the libraries above." >&2 + exit 1 + fi + publish: name: Publish release - needs: [build] + needs: [build, install] runs-on: ubuntu-26.04 timeout-minutes: 10 permissions: diff --git a/MIRROR.md b/MIRROR.md index 69ebe71eb211..25d486735b8b 100644 --- a/MIRROR.md +++ b/MIRROR.md @@ -62,6 +62,8 @@ The change lives in `mirror-patches/`, not as a commit on `main`. `main` therefo A `preflight` job checks the patches before the four build jobs start, so a stale patch costs two minutes instead of four long builds. +After the builds, an `install` job installs each package into a clean `debian:13` or `fedora:43` container and fails the release if the package's dependencies leave any of the app's libraries unresolved, or if the updater marker (`resources/package-type`) is missing. + ## When a patch goes stale Preflight files an issue labelled `mirror-patch` naming the patch and linking the failed run, then assigns GitHub Copilot to it. Copilot opens a pull request against `main` with the patch file rewritten against the new upstream code. From ac1825f3794af7c3070d2352175b2f05669d8db2 Mon Sep 17 00:00:00 2001 From: Tony <97451137+TonybynMp4@users.noreply.github.com> Date: Thu, 17 Sep 2026 11:01:19 +0200 Subject: [PATCH 7/7] ci(mirror): check patches against upstream tags before they are synced Co-Authored-By: Claude Opus 5 --- .github/workflows/mirror-patch-apply-check.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mirror-patch-apply-check.yml b/.github/workflows/mirror-patch-apply-check.yml index 78e36c1fcea5..9af06cef65c6 100644 --- a/.github/workflows/mirror-patch-apply-check.yml +++ b/.github/workflows/mirror-patch-apply-check.yml @@ -64,16 +64,18 @@ jobs: - name: Checkout upstream tag uses: actions/checkout@v6 with: + repository: pingdotgg/t3code ref: ${{ matrix.tag }} - name: Apply mirror patches shell: bash env: + MIRROR_REPO: ${{ github.server_url }}/${{ github.repository }} MIRROR_REF: ${{ github.ref }} run: | set -euo pipefail - git fetch --no-tags --depth=1 origin "$MIRROR_REF" + git fetch --no-tags --depth=1 "$MIRROR_REPO" "$MIRROR_REF" git checkout FETCH_HEAD -- \ mirror-patches \ .github/scripts/apply-mirror-patches.sh