a button beside the plugin count that becomes a URL field. everything after it is
the machinery that was already there: same installPlugin, same step and log
frames, same progress panel, same result.
STREAMED, because that is what "works exactly like it already does" means here.
an install writes an ecosystem entry, starts a process and rebuilds the router;
answering once at the end is a spinner that stops, with no way to tell "started
the sidecar" from "could not". the frame reader in usePlugins was split out
rather than copied — it never cared which URL it read from, and two copies of an
incomplete-frame parser is two places to get it subtly wrong.
A TWIN ROUTE, not a case inside the verb map. every other verb names an
INSTALLED plugin in its path; this one names something the machine has never
seen, and its subject arrives in the body. folding it in would mean a route whose
`:appName` is ignored for exactly one value of `:verb`.
NO NAME FIELD, deliberately. appName IS the directory a plugin sits in — never
declared in a manifest — so it decides the route segment, the table prefix and
the pm2 process name. a box for it would invite a name that disagrees with the
address. it is derived server-side and reported as the FIRST streamed step, which
is the moment it can still be cancelled.
collapsed until asked for: a permanent URL box at the top of a catalogue reads as
the primary way in, and it is the exception — for somebody who already has an
address.
verified end to end against fofos/fofos-admin: 30 frames, every step from clone
to mount, `assets: published to /plugins/fofos-admin/` now that it carries an
icon, and the icon served at 256x256 with alpha intact. purged afterwards —
officer-dev is not that website's machine.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043