ReviewOS

stacks/system-cleaner

Windows installs never auto-update: update.json only describes darwin

#31
Open glennmichael123 opened this 5 days ago ·
5 days ago

update.json is the file an installed copy fetches from releases/latest/download/update.json to learn it is behind. It carries a darwin entry and nothing else, so a Windows install has no update to find and stays where it is forever.

Both of the last two releases:

$ gh release download v0.3.10 --pattern update.json && jq '.platforms|keys' update.json
["darwin"]
$ gh release download v0.3.9  --pattern update.json && jq '.platforms|keys' update.json
["darwin"]

Not a regression — it has presumably been this way since the manifest was added. It is worth fixing now because of what it is currently stranding.

Why it matters right now

v0.3.9's Windows build cannot open a window at all. --system-tray was passed on every platform, and on Windows Craft reads that as "build a tray application", logs FailedToCreateWindow and opens nothing:

⚡ Creating system tray application
[2026-10-28T09:14:53Z] ERROR FailedToCreateWindow
no window within 60s

That is fixed in v0.3.10 (b8ad447), and SystemCleaner-0.3.10-windows-x64.zip is attached to the release. But the updater will not offer it, so anyone on 0.3.9 for Windows is sitting on an app that starts and shows nothing, with no route out except noticing by themselves and downloading the zip by hand. The one release where auto-update matters most is the one it cannot deliver.

Cause

scripts/build-desktop-app.ts names a single artifact:

const manifest = createGitHubUpdateManifest({
  repository: UPDATE_REPOSITORY,
  version: APP_VERSION,
  artifacts: { darwin: dmgPath },
})

It is not simply a missing key. That script runs in the desktop job, which needs a real Mac for codesign and notarytool, while the Windows zip is built in parallel by desktop-windows on a Windows runner. At the moment the manifest is written, the artifact it would have to describe does not exist on that machine and may not exist yet at all.

Suggested shape

.github/workflows/release.yml already solved this exact problem one asset over. The checksums job runs last:

checksums:
  name: Checksums
  needs: [release, desktop, desktop-windows]
  if: ${{ always() && needs.release.result == 'success' }}

and rebuilds checksums.txt over whatever actually landed, because two jobs each attaching their own partial copy meant the last writer won. The manifest has the same shape of problem and wants the same answer: assemble it once, last, from the assets actually on the release, rather than from whatever one builder could see.

Worth checking while in there:

  • whether the updater on Windows keys off platforms.win32, platforms.windows or something else, so the key written is the key it reads
  • the desktop job is skipped entirely when DESKTOP_SIGNING_IDENTITY_NAME is unset, which today also means no update.json at all; a manifest built in checksums would still describe the Windows asset in that case
  • a release with no signed macOS DMG should not publish a manifest claiming one

Verifying a fix

A fix should make this print both platforms:

$ gh release download <tag> --pattern update.json && jq '.platforms|keys' update.json

and the sha256 for each should match checksums.txt for the same asset. The macOS side is correct today and is worth keeping as the reference: in v0.3.10 the DMG hash in update.json matches checksums.txt and the downloaded file exactly.

Sign in to comment on this issue.