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', }, ], };