Settings gains an Updates block: it asks the church Gitea for the newest
release, compares the tag against the running build, and if there is a newer
one shows what changed and offers to download the installer.
Deliberately not electron-updater. That wants a static feed published beside
the artifacts, and this build is ad-hoc signed with no Team ID, so a silent
in-place swap would meet Gatekeeper on a machine nobody is sitting at. And
nothing here happens on its own: a background check that announces itself three
minutes into a sermon is a hazard, so the operator presses the button, and
presses a second one to download. The file lands in Downloads and is revealed;
installing is a drag across when the room is empty.
Tags are v<version>-<build>, compared numerically field by field so 3.9.0 does
not read as newer than 3.23.2 and build 113 beats build 112.
Two things only real testing found. Gitea answers with whatever address it was
reached on, so the release API returned asset URLs on 10.3.8.90 while the forge
is configured by hostname — the same-host guard refused a perfectly good
installer. The URL is now rebuilt on the configured origin, which keeps the
property that matters (this only ever fetches from the server the operator
configured) and survives a forge that knows itself by more than one name. And a
private repository answers 404 rather than 401, so 'no releases published yet'
told the operator the opposite of the truth; without a token that case now names
the remedy instead.
The token is this machine's credential: it stays out of PORTABLE_APP, so it does
not ride along in an exported settings file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>