diff --git a/commanders/convert-on-arrival/watch.sh b/commanders/convert-on-arrival/watch.sh index cb493c1..e5068e9 100755 --- a/commanders/convert-on-arrival/watch.sh +++ b/commanders/convert-on-arrival/watch.sh @@ -13,8 +13,15 @@ set -uo pipefail -STATE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/state" +HOME_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +STATE="$HOME_DIR/state" CONFIG="$STATE/config.env" + +# The commander's own credential, written beside this script when the directory was created. Two files +# rather than one because they have different lifetimes: `officer.env` is minted by the platform and can +# be re-minted without touching what the owner configured, and `config.env` is the owner's answers and +# must survive that. Sourcing both is the join. +CREDENTIAL="$HOME_DIR/officer.env" LOG="$STATE/convert.log" SEEN="$STATE/converted.list" @@ -22,6 +29,15 @@ SEEN="$STATE/converted.list" # shellcheck disable=SC1090 source "$CONFIG" +# shellcheck disable=SC1090 +[[ -f "$CREDENTIAL" ]] && source "$CREDENTIAL" + +# The platform writes the key as OFFICER_API_KEY. This script asks for OFFICER_AUTH_TOKEN because that +# is what a TASK is given, and the two names are the same secret from two directions. Bridged here +# rather than renamed in either place: a commander sources the platform's file and a task reads the +# platform's env, and neither is this plugin's to rename. +: "${OFFICER_AUTH_TOKEN:=${OFFICER_API_KEY:-}}" + : "${WATCH_DIR:?WATCH_DIR is not set}" : "${EXTENSIONS:=heic,heif}" : "${OUTPUT_FORMAT:=webp}" diff --git a/manifest.ts b/manifest.ts index 86a2024..bd0cb88 100644 --- a/manifest.ts +++ b/manifest.ts @@ -36,6 +36,54 @@ export const manifest: PluginManifest = { `npm-deps.ts` collects these across every plugin into `plugins/node_modules/`, so atelier's copy of sharp is the one used here too rather than a second 50 MB of platform binaries. */ + /* + ── The two the machine must already have, and the one that is easy to miss ── + + ffmpeg and ImageMagick are obvious: everything video goes through the first, and the second is how + HEIC gets decoded at all (see sidecar/sharp/decodable.ts — sharp's bundled libheif is built without + the HEVC decoder, so ImageMagick's system libheif does that work). + + `libheif-plugin-libde265` is the one nobody would guess, and it is declared here because it cost an + hour to find. libheif is packaged with its CODECS AS SEPARATE PLUGINS: `libheif1` alone parses a + HEIC container and reports its dimensions, and then fails on the pixels with "Unsupported codec". + Ubuntu ships `libheif-plugin-aomdec` (AV1) in the common install and NOT the HEVC one — which is + what every iPhone actually writes. + + Observed 2026-08-29: identical libheif 1.17.6 on two hosts, HEIC working on one and not the other, + the only difference being this package. A plugin that silently half-works on some machines is worse + than one that refuses to install, so it is declared rather than left to luck. + + No `binary:` that means anything on its own — it is a shared library plugin, not a command. The + binary named is the one that USES it, which is what makes the check meaningful. + */ + osDependencies: [ + { + binary: 'ffmpeg', + reason: 'Every video and audio conversion. Without it, only images work.', + packages: { apt: 'ffmpeg', pacman: 'ffmpeg', dnf: 'ffmpeg', brew: 'ffmpeg' }, + }, + { + binary: 'convert', + reason: 'Decodes HEIC, which sharp cannot — see sidecar/sharp/decodable.ts.', + /* + No `dnf`. Fedora's package is literally `ImageMagick`, with capitals, and the manifest validator + refuses an uppercase package name — deliberately, since these strings reach a root command line + and the rule is a closed vocabulary rather than a filter. + + Omitted rather than worked around: naming `imagemagick` there would be naming a package that does + not exist, which fails at install time on the one distribution it was meant to help. The manifest + documentation says a case like this "wants a conversation, not a regex that already allows it", + and this is that case being left for the conversation. + */ + packages: { apt: 'imagemagick', pacman: 'imagemagick', brew: 'imagemagick' }, + }, + { + binary: 'convert', + reason: "libheif's HEVC decoder. Without it a HEIC parses and then fails on its pixels.", + packages: { apt: 'libheif-plugin-libde265' }, + }, + ], + npmDependencies: { sharp: '^0.35.3', },