From 04e426c4482b2bc1baf8c1434258e1a585665d65 Mon Sep 17 00:00:00 2001 From: Marcin Sadowski Date: Tue, 10 Nov 2026 18:53:41 +0100 Subject: [PATCH 1/3] feat: publish the Apple silicon build as Lantern-mac-arm64.zip for the updater --- .../2026-11-10-mac-arm64-asset/HANDOFF.md | 5 ++++ .ai/runs/2026-11-10-mac-arm64-asset/PLAN.md | 13 ++++++++ .github/workflows/release.yml | 8 +++++ README.md | 3 +- docs/installation.md | 6 ++-- test/release-workflow.test.ts | 30 +++++++++++++++++++ 6 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 .ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md create mode 100644 .ai/runs/2026-11-10-mac-arm64-asset/PLAN.md diff --git a/.ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md b/.ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md new file mode 100644 index 0000000..660dd9a --- /dev/null +++ b/.ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md @@ -0,0 +1,5 @@ +# Handoff + +Plan unreviewed (unattended run). The publish job copies the downloaded Lantern-mac.zip to +Lantern-mac-arm64.zip before the upload; tests and docs follow. update.electronjs.org rule verified in +src/asset-platform.ts. Workflow not run. diff --git a/.ai/runs/2026-11-10-mac-arm64-asset/PLAN.md b/.ai/runs/2026-11-10-mac-arm64-asset/PLAN.md new file mode 100644 index 0000000..0bae3a0 --- /dev/null +++ b/.ai/runs/2026-11-10-mac-arm64-asset/PLAN.md @@ -0,0 +1,13 @@ +## Tasks + +| # | Step | Status | Commit | +|---|---|---|---| +| 1 | Copy Lantern-mac.zip to Lantern-mac-arm64.zip in the publish job, guard it in the test, say it in the docs | done | see git log | + +## Validation + +`pnpm run typecheck`, `pnpm run lint`, `pnpm test` + +## Non-goals + +build-mac, signing scripts, entitlements, updater, dependencies, versions, tags. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1728f3d..0969194 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -149,6 +149,14 @@ jobs: *) echo "Tag '$TAG' does not start with v"; exit 1 ;; esac + - name: Publish the Apple silicon build under the name the updater looks for + run: | + if [ ! -f release-assets/Lantern-mac.zip ]; then + echo "release-assets/Lantern-mac.zip is missing, nothing to copy to Lantern-mac-arm64.zip" + exit 1 + fi + cp release-assets/Lantern-mac.zip release-assets/Lantern-mac-arm64.zip + - name: Create the release when it is missing run: | if ! gh release view "$TAG" > /dev/null 2>&1; then diff --git a/README.md b/README.md index 9d37440..73f3e25 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ Sessions are told apart by their working directory: one entry per VS Code projec Packages are attached to each release on the [releases page](https://github.com/MobileReality/lantern/releases): `Lantern-mac.zip` for -Apple-silicon Macs and `Lantern-win-x64.zip` for Windows. Until a release is published there, +Apple-silicon Macs and `Lantern-win-x64.zip` for Windows. The Apple-silicon build is also published +as `Lantern-mac-arm64.zip` for the updater, and the `Lantern-mac.zip` link stays the one to use. Until a release is published there, build Lantern from source ([installation](docs/installation.md#install-and-run-from-source)). The macOS app of a release built by the current workflow is signed with a Developer ID certificate diff --git a/docs/installation.md b/docs/installation.md index 2ecc482..03a415c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -14,7 +14,8 @@ the app itself, see [getting-started.md](getting-started.md). Packages are attached to each release on the [releases page](https://github.com/MobileReality/lantern/releases): `Lantern-mac.zip` for -Apple-silicon Macs and `Lantern-win-x64.zip` for Windows. Until a release is published there, +Apple-silicon Macs and `Lantern-win-x64.zip` for Windows. The Apple-silicon build is also published +as `Lantern-mac-arm64.zip` for the updater, and the `Lantern-mac.zip` link stays the one to use. Until a release is published there, build Lantern from source as described below. The macOS app of a release built by the current workflow is signed with a Developer ID certificate @@ -61,7 +62,8 @@ runs the same package scripts as a local build. On a macOS runner, `pnpm run bui `pnpm run fuses` build the app, `scripts/mac-sign-notarize.sh` signs and notarizes it, and `pnpm run pack` gives `Lantern-mac.zip` (Apple silicon). `pnpm run build:win` on a Windows runner gives `Lantern-win-x64.zip`. A last job creates the release for the tag when it is missing, with -generated release notes, and uploads both files; running it again replaces them. +generated release notes, copies `Lantern-mac.zip` to `Lantern-mac-arm64.zip` (the name the updater +needs to find the Apple-silicon build) and uploads the three files; running it again replaces them. - **Release a new version**: push a tag that starts with `v`, for example `git tag v0.2.1 && git push origin v0.2.1`. The workflow starts on the push, and the macOS job diff --git a/test/release-workflow.test.ts b/test/release-workflow.test.ts index f9dd623..c7b20f4 100644 --- a/test/release-workflow.test.ts +++ b/test/release-workflow.test.ts @@ -109,6 +109,36 @@ describe('release workflow, the signing job', () => { }); }); +describe('release workflow, the publish job', () => { + const PUBLISH = WORKFLOW.jobs.publish.steps; + const copyIndex = PUBLISH.findIndex((step) => step.run?.includes('Lantern-mac-arm64.zip') && step.run.includes('cp ')); + const uploadIndex = PUBLISH.findIndex((step) => step.run?.includes('gh release upload')); + + it('copies Lantern-mac.zip to Lantern-mac-arm64.zip before the upload, and fails when the source is missing', () => { + expect(copyIndex).toBeGreaterThanOrEqual(0); + expect(copyIndex).toBeLessThan(uploadIndex); + const copy = PUBLISH[copyIndex].run ?? ''; + expect(copy).toContain('cp release-assets/Lantern-mac.zip release-assets/Lantern-mac-arm64.zip'); + expect(copy).toMatch(/\[ ! -f release-assets\/Lantern-mac\.zip \]/); + expect(copy).toContain('exit 1'); + }); + + it('uploads everything in the assets folder with --clobber, so the stable names and the arm64 copy all go up', () => { + expect(uploadIndex).toBeGreaterThanOrEqual(0); + expect(PUBLISH[uploadIndex].run).toContain('release-assets/* --clobber'); + const uploadedByBuilds = Object.values(WORKFLOW.jobs) + .flatMap((job) => job.steps) + .filter((step) => step.uses?.startsWith('actions/upload-artifact@')) + .map((step) => step.with?.path); + expect(uploadedByBuilds.sort()).toEqual(['dist/Lantern-mac.zip', 'dist/Lantern-win-x64.zip']); + }); + + it('builds and signs nothing in the publish job', () => { + expect(PUBLISH.map((step) => step.run ?? '').join('\n')).not.toMatch(/pnpm|mac-sign-notarize|codesign|notarytool/); + expect(PUBLISH.some(readsSecret)).toBe(false); + }); +}); + describe('mac entitlements', () => { const keysOf = (file: string) => [...read(file).matchAll(/([^<]+)<\/key>/g)].map((match) => match[1]).sort(); From 4ebb126a4a308f49801f78634048d69e7d7ffbf3 Mon Sep 17 00:00:00 2001 From: Marcin Sadowski Date: Tue, 10 Nov 2026 18:56:06 +0100 Subject: [PATCH 2/3] chore: update the Lantern map --- .ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md | 5 ----- .ai/runs/2026-11-10-mac-arm64-asset/PLAN.md | 13 ------------- .lantern/lang/en/.github/workflows.lantern.json | 2 +- .lantern/map/.github/workflows.lantern | 2 +- .lantern/map/test.lantern | 2 +- 5 files changed, 3 insertions(+), 21 deletions(-) delete mode 100644 .ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md delete mode 100644 .ai/runs/2026-11-10-mac-arm64-asset/PLAN.md diff --git a/.ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md b/.ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md deleted file mode 100644 index 660dd9a..0000000 --- a/.ai/runs/2026-11-10-mac-arm64-asset/HANDOFF.md +++ /dev/null @@ -1,5 +0,0 @@ -# Handoff - -Plan unreviewed (unattended run). The publish job copies the downloaded Lantern-mac.zip to -Lantern-mac-arm64.zip before the upload; tests and docs follow. update.electronjs.org rule verified in -src/asset-platform.ts. Workflow not run. diff --git a/.ai/runs/2026-11-10-mac-arm64-asset/PLAN.md b/.ai/runs/2026-11-10-mac-arm64-asset/PLAN.md deleted file mode 100644 index 0bae3a0..0000000 --- a/.ai/runs/2026-11-10-mac-arm64-asset/PLAN.md +++ /dev/null @@ -1,13 +0,0 @@ -## Tasks - -| # | Step | Status | Commit | -|---|---|---|---| -| 1 | Copy Lantern-mac.zip to Lantern-mac-arm64.zip in the publish job, guard it in the test, say it in the docs | done | see git log | - -## Validation - -`pnpm run typecheck`, `pnpm run lint`, `pnpm test` - -## Non-goals - -build-mac, signing scripts, entitlements, updater, dependencies, versions, tags. diff --git a/.lantern/lang/en/.github/workflows.lantern.json b/.lantern/lang/en/.github/workflows.lantern.json index 9407074..07b204c 100644 --- a/.lantern/lang/en/.github/workflows.lantern.json +++ b/.lantern/lang/en/.github/workflows.lantern.json @@ -3,6 +3,6 @@ "ci.yml": "Runs the install, typecheck, lint and unit tests, the headless Playwright e2e suites and a unit-test coverage run that is uploaded as an artifact, plus builds and packaging on Ubuntu, macOS and Windows runners, on every push and pull request with SHA-pinned actions", "codeql.yml": "Scans the JavaScript and TypeScript sources with CodeQL on pushes to main, on pull requests and weekly, with read-only contents access, write access to security events only and SHA-pinned actions", "deploy-docs.yml": "Builds the documentation site on every change to its sources and on pull requests, and publishes it to GitHub Pages from main with SHA-pinned actions, defaulting the site URL to docs.thelantern.dev", - "release.yml": "Builds the macOS and Windows packages when a v* tag is pushed or a tag is chosen by hand, signing and notarizing the macOS app in the protected release environment only from a v* tag, and attaches them to that tag's GitHub Release, which is created with generated notes when missing" + "release.yml": "Builds the macOS and Windows packages when a v* tag is pushed or a tag is chosen by hand, signing and notarizing the macOS app in the protected release environment only from a v* tag, and attaches them, plus a copy of the macOS zip named for Apple silicon so the updater finds it, to that tag's GitHub Release, which is created with generated notes when missing" } } diff --git a/.lantern/map/.github/workflows.lantern b/.lantern/map/.github/workflows.lantern index 2bd7a90..573daa4 100644 --- a/.lantern/map/.github/workflows.lantern +++ b/.lantern/map/.github/workflows.lantern @@ -8,7 +8,7 @@ lantern 1 .github/workflows/deploy-docs.yml . infra 41b0263d580d > website/package.json -.github/workflows/release.yml . infra c4bd3239b533 +.github/workflows/release.yml . infra 41d03418640d > package.json > scripts/mac-ci-keychain.sh > scripts/mac-sign-notarize.sh diff --git a/.lantern/map/test.lantern b/.lantern/map/test.lantern index 9b52daf..b8082b1 100644 --- a/.lantern/map/test.lantern +++ b/.lantern/map/test.lantern @@ -2011,7 +2011,7 @@ test/reason-definition.test.ts . test 550e8f81a437 = src/shared/reason.ts < skills/lantern-setup/scripts/prs.mjs#REASON_MAX_CHARS -test/release-workflow.test.ts . test 4e110666c136 +test/release-workflow.test.ts . test 3d985cb8cdbb < .github/workflows/release.yml < scripts/mac-sign-notarize.sh From fafd2a48ccf656e4a64b42a20d3e5b4a4b5c502d Mon Sep 17 00:00:00 2001 From: Marcin Sadowski Date: Tue, 10 Nov 2026 18:57:37 +0100 Subject: [PATCH 3/3] chore: record pull request #30 in the Lantern map --- .lantern/prs/30.pr | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .lantern/prs/30.pr diff --git a/.lantern/prs/30.pr b/.lantern/prs/30.pr new file mode 100644 index 0000000..08cf1fe --- /dev/null +++ b/.lantern/prs/30.pr @@ -0,0 +1,35 @@ +lantern-pr 1 +# 30 +#title Publish the Apple silicon build as Lantern-mac-arm64.zip for the updater +#url https://github.com/MobileReality/lantern/pull/30 +#branch feat/mac-arm64-release-asset +#base main +#opened 2026-11-10 +#head 4ebb126a4a308f49801f78634048d69e7d7ffbf3 +#describe what Every release gets Lantern-mac-arm64.zip, a byte-identical copy of Lantern-mac.zip, so the updater can find the Apple silicon build. +#describe before Releases had Lantern-mac.zip and Lantern-win-x64.zip; darwin-arm64 answered 404. +#describe after Releases have three assets; Lantern-mac.zip stays the download link. +#describe verified typecheck, lint and pnpm test are green; the release workflow was not run. +~ .github/workflows/release.yml +~ README.md +~ docs/installation.md +~ test/release-workflow.test.ts +#order .github/workflows/release.yml +#order test/release-workflow.test.ts +#order README.md +#order docs/installation.md +#reason .github/workflows/release.yml The updater files a darwin zip as arm64 only when the name has -arm64, so Apple silicon got a 404. +#reason README.md Tells readers the Apple silicon build is also published as Lantern-mac-arm64.zip for the updater. +#reason docs/installation.md Keeps the release description true now that the publish job adds a third file. +#reason test/release-workflow.test.ts Guards that the copy exists, runs before the upload, and fails when the source is missing. +#story Apple silicon Macs find updates +#step actor A maintainer pushes a v* tag +#file .github/workflows/release.yml +#step action The release also publishes the Mac zip as Lantern-mac-arm64.zip +#file .github/workflows/release.yml +#file test/release-workflow.test.ts +#step subject The release page +#file README.md +#file docs/installation.md +#below interaction Apple silicon users are offered the update +#below consequence The update check answered not found => The update check finds the build