macOS bundle: drop Info.plist UTI declarations LightCraft cannot open (#1951)

The template was copied from a sibling app: it exported a "LightCraft Document"
UTI for PhotoCraft's `.pcraft` extension (MIME `application/x-lightcraft`) and
imported `.psb` (Photoshop Large Document) and `.qoi`. LightCraft reads none of
them, so the declarations only made Launch Services type PhotoCraft documents as
LightCraft's and left `.pcraft` with three claimant apps among the Craft suite.

Remove both `UTExportedTypeDeclarations` and `UTImportedTypeDeclarations`. No
CFBundleDocumentTypes is added: the formats LightCraft opens are already declared
by the system or another app, so adding them is out of scope here.

`packaging/check-app-specific.sh` now parses the template as a property list and
fails if it declares any of those types again, while still checking the required
bundle keys.

Co-Authored-By: DeepSeek V4.1 Flash <noreply@deepseek.com>
This commit is contained in:
Sergio Perea
2026-10-16 09:07:29 +02:00
co-authored by DeepSeek V4.1 Flash
parent f34c7a8a89
commit fa26767b81
2 changed files with 43 additions and 60 deletions
+38
View File
@@ -22,3 +22,41 @@ for key in ("runtime", "runtime-version", "sdk", "finish-args"):
assert manifests[0][key] == manifests[1][key], f"Flatpak manifests disagree on {key}"
print("LightCraft package identity ok")
PYEOF
# The macOS bundle must declare only file types LightCraft can open. It used to carry PhotoCraft's
# `.pcraft` document type and imported PSB/QOI declarations, so Launch Services typed PhotoCraft
# documents as LightCraft's and `.pcraft` had three claimant apps (issue #1951). plistlib parses the
# template as a property list too, which is the syntax check package.sh's `plutil -lint` repeats on
# the substituted file.
python3 - <<'PYEOF'
import plistlib
with open("packaging/macos/Info.plist.in", "rb") as source:
plist = plistlib.load(source)
for key, value in {
"CFBundleIdentifier": "ai.storyteller.lightcraft",
"CFBundleExecutable": "LightCraft",
"CFBundleIconFile": "LightCraft",
"LSMinimumSystemVersion": "11.0",
}.items():
assert plist.get(key) == value, f"Info.plist {key}: {plist.get(key)!r}, expected {value!r}"
for key in ("CFBundleShortVersionString", "CFBundleVersion", "LightCraftVersion", "LightCraftBuildCommit"):
assert plist.get(key), f"Info.plist lost {key}"
declared = set()
for section in ("UTExportedTypeDeclarations", "UTImportedTypeDeclarations"):
for entry in plist.get(section, []):
tags = entry.get("UTTypeTagSpecification", {})
declared.update(tags.get("public.filename-extension", []))
declared.update(tags.get("public.mime-type", []))
declared.add(entry.get("UTTypeIdentifier", ""))
unsupported = {name.lower() for name in declared} & {
"pcraft",
"psb",
"qoi",
"application/x-lightcraft",
"ai.storyteller.lightcraft.document",
"ai.storyteller.lightcraft.qoi",
"com.adobe.photoshop-large-image",
}
assert not unsupported, f"Info.plist declares types LightCraft cannot open: {sorted(unsupported)}"
print("LightCraft macOS bundle types ok")
PYEOF
+5 -60
View File
@@ -49,66 +49,11 @@
<key>NSHumanReadableCopyright</key>
<string>Copyright © the LightCraft authors. MIT OR Apache-2.0.</string>
<!-- Lightcraft's own format. -->
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>ai.storyteller.lightcraft.document</string>
<key>UTTypeDescription</key>
<string>LightCraft Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.image</string>
</array>
<key>UTTypeIconFile</key>
<string>LightCraft</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array><string>pcraft</string></array>
<key>public.mime-type</key>
<array><string>application/x-lightcraft</string></array>
</dict>
</dict>
</array>
<!-- Types macOS may not know; the system's own declaration wins when it has one. -->
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>com.adobe.photoshop-large-image</string>
<key>UTTypeDescription</key>
<string>Photoshop Large Document</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.image</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array><string>psb</string></array>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>ai.storyteller.lightcraft.qoi</string>
<key>UTTypeDescription</key>
<string>QOI Image</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.image</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array><string>qoi</string></array>
</dict>
</dict>
</array>
<!-- No UTI declarations: LightCraft has no document type of its own, and the formats it opens
(JPEG, PNG, TIFF, HEIC, the raw formats) are declared by the system or by another app.
Declaring PhotoCraft's `.pcraft` type here (and importing PSB and QOI) made Launch Services
type PhotoCraft documents as LightCraft's; `.pcraft` ended up with three claimant apps
(issue #1951). -->
</dict>
</plist>