TWO BUGS, one in each half. the watcher demanded OFFICER_AUTH_TOKEN and nothing supplied it. the commander's credential is written to `officer.env` beside the script, under OFFICER_API_KEY — a sibling file this never sourced. so a commander created from this template would have died on its first tick with "OFFICER_AUTH_TOKEN is not set", and I had missed it by appending the values by hand while testing, which is exactly how a thing looks like it works. two files rather than one because they have different lifetimes: officer.env is the platform's and can be re-minted, config.env is the owner's answers and must survive that. the name is bridged in the script rather than renamed at either end — a commander sources the platform's file and a task reads the platform's env, and neither is this plugin's to rename. AND libheif-plugin-libde265 IS NOW DECLARED, which cost an hour to find. libheif packages its CODECS SEPARATELY: `libheif1` alone parses a HEIC container and reports 4032x3024, then fails on the pixels with "Unsupported codec". ubuntu ships the AV1 plugin in the common install and not the HEVC one — which is what every iPhone actually writes. observed today: identical libheif 1.17.6 on two hosts, HEIC decoding on fofos and not on officer-dev, the only difference being that package. a plugin that silently half-works on some machines is worse than one that refuses to install. no dnf entry for imagemagick. fedora's package is literally `ImageMagick` with capitals and the manifest validator refuses uppercase — correctly, since these strings reach a root command line as a closed vocabulary. naming `imagemagick` there would name a package that does not exist. left for the conversation the manifest documentation says a case like this wants. the validator caught that on the way through, and discovery refused the plugin until it was fixed. verified after: no problems, no broken plugins, 3 osDeps read back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
4.6 KiB
TypeScript
98 lines
4.6 KiB
TypeScript
import type { PluginManifest } from '@@/plugins/manifest';
|
|
|
|
/**
|
|
* av-club — sharp, ffmpeg and ffprobe over HTTP, for whoever needs to turn an upload into something a
|
|
* browser can serve.
|
|
*
|
|
* ── No screens, deliberately ──
|
|
*
|
|
* This is an API and a body of documentation, not a place to click. Its callers are a commander watching
|
|
* an upload folder, an agent, or a person with curl. A dock tile would advertise a page that has nothing
|
|
* to show — the work happens where the files are, which is not here.
|
|
*
|
|
* ── One permission, and it is not `personal` ──
|
|
*
|
|
* Every other permission's paths act on the caller's own data. These act on assets av-club itself issued
|
|
* ids for, in its own store, shared by every caller — so it is an ordinary grantable capability rather
|
|
* than a per-account one, and an account without it cannot reach the encoder at all.
|
|
*/
|
|
export const manifest: PluginManifest = {
|
|
publisher: 'officerdev',
|
|
version: '2026.08.28.01',
|
|
platform: '>=1.0.0',
|
|
label: 'AV Club',
|
|
summary: 'Convert and treat images, video and audio — sharp, ffmpeg and ffprobe behind one API',
|
|
tags: ['Development', 'Personal'],
|
|
icon: 'Clapperboard',
|
|
color: '#8b5cf6',
|
|
/*
|
|
Declared HERE rather than in a package.json, and that is not a style choice.
|
|
|
|
A package.json inside a plugin makes a package boundary, and Bun then stops walking up for the
|
|
platform's tsconfig — so `@@/sidecar/connect` stops resolving and the sidecar dies on its first
|
|
import. That is exactly how this plugin failed on the day it was extracted: it arrived carrying its
|
|
own package.json and bun.lock, and both the router and the sidecar could not find the platform.
|
|
|
|
`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',
|
|
},
|
|
permissions: [
|
|
{
|
|
key: 'av-club',
|
|
label: 'AV Club',
|
|
description: 'Convert and inspect media through sharp, ffmpeg and ffprobe',
|
|
},
|
|
],
|
|
};
|