a plugin can depend on a release binary, and prove it is the right one

osDependencies could only say "this package, from this manager". Gitea's `tea`
is not in any distribution — it is a Go binary from dl.gitea.com — and Debian
has an UNRELATED package of that name: a graphical text editor. So the one
dependency gitea actually wants could not be expressed, and its marketplace
page showed no dependencies at all while music's showed two.

`release: { url, identify }` covers it. {os} and {arch} are filled from the
host in the spelling Go releases use, and the binary is fetched to
~/.local/bin — no root, and nothing a plugin downloaded from the internet
sitting beside what the distribution installed. Written to a temporary name and
moved into place, so a half-downloaded file is never on PATH under the real
one.

`identify` is the part that matters. Bun.which('tea') cannot tell Gitea's CLI
from the text editor, so presence was never the same question as identity —
and reporting the wrong program as satisfied is worse than reporting it
missing, because the install succeeds and every call afterwards fails
strangely. A binary that fails to identify is now `present: false, imposter:
true`.

Found while testing: Bun.which() with no options reads the PATH the PROCESS
started with, which under PM2 frequently excludes ~/.local/bin entirely. A
release binary fetched during an install would have been reported missing
seconds later by stillMissing, failing an install that had just succeeded. The
search now passes PATH explicitly, with ~/.local/bin first.

Verified against the real binaries on this machine: the genuine tea identifies,
a fake that prints text-editor output is caught as an imposter, and both
dl.gitea.com URLs (linux-amd64, darwin-arm64) answer 200.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 08:48:18 +00:00
co-authored by Claude Opus 5
parent 51afa40a19
commit 09f2cfa267
5 changed files with 277 additions and 9 deletions
+16
View File
@@ -298,6 +298,22 @@ pane belonging to the folder you left; and the breadcrumb opted out of that last
restored. Deliberate as written — a dashboard can hold two browsers and one URL cannot serve both —
but worth re-deciding rather than inheriting.
## Release-binary dependencies (2026-08-19)
Built: a plugin can declare `release: { url, identify }` for a dependency no package manager carries.
Gitea's `tea` is the motivating case and the first user.
Two things it does NOT do, both deliberate and both worth knowing:
- **No checksum.** The download is verified by RUNNING it through the same `identify` rule the probe
uses, which catches an HTML error page, a truncated file and a wrong-architecture build — none of them
print what the plugin said to look for. It does not catch a compromised upstream. A checksum per
os/arch is a table that goes stale every release and would stop installs the day upstream re-cuts a
tag; HTTPS and a URL the owner reads in the install dialog is what stands behind it today.
- **The version is pinned in the manifest.** `tea` is fixed at 0.15.1, so a new release needs a plugin
update. That is the right default — an install that silently fetches whatever is latest is not
reproducible — but there is no "check for a newer one" anywhere.
## Affordances (2026-08-19)
Agreed and written down in `plugins/CLAUDE.md`; **nothing is built**. An affordance is what the surface