packages::find tried each bundle id across every record, so a system
io.tangencylabs.solidcraft beat a user ai.storyteller.solidcraft. Packages now say
whether they're a user install; find looks through the user ones first, current id
first within each scope.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1071 moved release checks to twelve minutes and changed this test to match, but detection runs on RESCAN_EVERY in app.rs, a separate timer that stayed at five. The test has failed on main since.
AGENTS.md (and CLAUDE.md where present) gets a CI workflows section: workflows only call
craft-common-actions at @main, with no other jobs; feature and fix PRs don't touch CI and
link or open a craft-common-actions issue (a PR only for a small fix that is safe for
every app and does not increase CI time); legacy jobs
aren't added to and move only as their own task, staying until a shared workflow runs them.
Flatpak mounts the host's /usr/share/fonts at /run/host/fonts and
/usr/local/share/fonts at /run/host/local-fonts (add_font_path_args in
flatpak's common/flatpak-run.c). The sandbox's own /usr/share/fonts holds
only the runtime's fonts, so the Flatpak launcher found no Chinese or
Japanese font and fell back to English.
Each system candidate is now followed by its /run/host path, for the same
family. User fonts need no twin, since both manifests grant
--filesystem=home. PhotoCraft fixed the same lookup in
storytold/photocraft#1204.
An AppImage the launcher installed is renamed into place whole, and the old file is removed
only after that, the same as an update. Going back to a version chosen by name now takes
that route too (Downgrade::KeepOldCopy), with no older package fetched first. It needs the
launcher's own record of an AppImage: a user's own AppImage, an unrecorded one and the
tarball install (whose bin and share swap one at a time) are still refused.
Not run on a real Linux desktop; the linux module only compiles there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The window sets its app id (Wayland) and WM_CLASS (X11) to
ai.storyteller.artcraft-launcher, but the entry said
StartupWMClass=artcraft-launcher. Desktops that find the entry by its
file name were fine; an entry under another name (AppImageLauncher,
Gear Lever, a hand-made one) never matched, so the dock showed a
generic icon and the launcher could not be pinned.
pkexec exits 126 when the prompt is dismissed. 127 is its default code and
also covers not authorized and no authentication agent, so a desktop with no
polkit agent ended an install as a quiet "Install cancelled" with no prompt.
get_api shared the 4 MiB limit for small answers, and SolidCraft's list of 67
releases is 5.4 to 6.5 MB. The request failed every time, so Choose version
showed an error and no versions. Other small requests keep 4 MiB.
Dates ran to 130 px in Brazilian Portuguese and 108 px in Chinese and
Japanese, past the 104 px column, and were cut with an ellipsis. The
column is now 132 px; Author gives up 16 px ("Tangency Labs" still fits)
and the app column 12 px.
Flatpak mounts an app's read-only grant for ArtCraft/versions only when the
folder exists as the app starts. The launcher now makes it on start, and its
Flatpak grants xdg-data/ArtCraft/versions with :create, which also covers an
XDG_DATA_HOME outside home, where --filesystem=home does not reach.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
craft-update 9817c81 moves versions.json to ArtCraft/versions under the host's
per-user data folder, resolved from inside the Flatpak too, so a Flatpak
launcher writes where host apps and granted Flatpak apps read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SolidCraft's macOS build has been Developer ID signed and notarized since 0.27 (its README),
but the launcher still treated it as unsigned (`installs_on_mac: false`), so on a Mac it
offered the update and then said no macOS version was available.
`installs_on_mac` becomes `mac_team`: the Apple team whose signature the build must carry.
Official apps keep ArtCraft's (DJ6XS33FX8); SolidCraft gets its own (G5QA5U5X2S, read from
the signature on its 0.27.1 macOS CLI). `None` still means the launcher installs no DMG, and
an install that reaches the DMG path without a team is now refused, not left unchecked.
Not run on a real Mac: the macos module only compiles there, and the DMG's own signature
still needs `codesign -dv` on a Mac to confirm the team matches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only tarball apps on Linux were given CRAFT_VERSIONS_FILE. Now every launch
route passes it: Windows (exe and MSI) and AppImages through the process
environment, Flatpak apps through `flatpak run --env=`, and anything the
Flatpak launcher starts on the host through `flatpak-spawn --env=`. macOS
apps open through Launch Services with the real home, so they find the file
at its default path; `open` is left unchanged since not every macOS version
takes an environment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A version chosen in the launcher lived only in its own settings, so an app's
own update check (craft-update's Updater) still offered the latest release on
every start, and accepting it undid the downgrade.
The backend now writes craft_update::pins' shared file on every Configure:
each app's track from the settings, stable ones removed, entries a newer
launcher wrote kept. The first Configure after an upgrade moves choices saved
earlier. A tarball app on Linux, whose data folder points into its own home,
is told the real file through CRAFT_VERSIONS_FILE.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pins craft-update to storytold/craft-libs#449 (0ada678) for craft_update::pins.
Bump to the merged commit once that PR lands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `rustls-webpki`: 0.103.15 → 0.103.16
- `zip`: 8.6.0, 9.1.0 → 9.1.3
Requirement `zip` 8 → 9. The portable-ZIP check now treats an entry name that doesn't decode as unsafe, like one with `\\` or `:`. That code is Windows-only and wasn't compiled here (Linux); Windows CI is the check.
A Mac update already moves the installed .app aside, renames the new bundle in and moves
the old one back if that fails. Going back to a version chosen by name now uses the same
swap for a DMG over a Mac app install, so no older package has to be found and fetched
first. Downgrade becomes an enum: Reinstall (the Windows Installer route, unchanged) and
KeepOldCopy (macOS). Each is let through only for the install it can undo; anything else
is still refused before anything is downloaded.
Not run on a real Mac: the macos module only compiles there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two review findings, both ways for the 'app left uninstalled' trap to come back:
- If the one-prompt elevated session could not start, an all-users downgrade fell back to a
prompt per step. It now stops before anything is removed and says nothing was changed.
- The step-by-step route (per-user copies) took a separate installer-queue turn per step, so
another queued install, or a cancel while waiting, could stop the put-back after the copy
was removed. Remove, install and put-back now run in one turn, with nothing to wait on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An app can be registered more than once (per-user and all-users). If removing one succeeded
and the next failed, both downgrade routes stopped there, said nothing had changed, and never
put the previous version back. Now a removal that fails after another succeeded reinstalls
the previous version, in the elevated script and the step-by-step route, and says so with
outcomes of its own. A first removal that fails still changes nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>