CapabilityInstaller
The route the panel's Install button posts to. The panel listed what a house could grow and offered a button that answered 404, because `capabilities:enable` reaches HTTP only when the APP names it in `config/http.php` — and a fresh app names nothing. The button told the truth about it and pointed at the command, which is honest and is not station 4: the whole point of that station is equipping the house FROM the panel (greenhouse decisions/0248). So the panel mounts what its own button needs, exactly as it already mounts its page and its assets. The app's global operations surface is untouched: nothing else becomes reachable, and a house that exposes nothing keeps exposing nothing. ── THE TWO GATES ARE BOTH KEPT, AND THAT IS THE CONDITION FOR DOING IT THIS WAY ──────────────── - the NETWORK gate — this route carries the panel's own middleware, loopback-only by default, the same one that decides who may look at the panel at all; - the CONSENT gate — the operation still demands its confirmation: the first POST answers `requires_confirmation` with a token and does nothing, and only a second POST carrying that token proceeds. The ceremony is the projector's, not a copy: a second implementation of one act could only ever be the wrong one. Mounting a route grants no authority (`decisions/0240`, invariant 1). The operation goes on declaring what it declares — privileged, downloads third-party code, manual recovery — and the gate reads that. ── WHY IT DELEGATES INSTEAD OF BEING A PROJECTOR ────────────────────────────────────────────── `HttpProjector` resolves which operation to run from the matched ROUTE NAME, and it registers under its own class so every projected route resolves to one instance. Two packages each mounting their own would leave one set of routes resolving against an instance that has never heard of their operations — a 404 with no error anywhere, which is exactly the failure this class exists to remove. So the panel keeps its own class key, its own path and its own route name, and supplies the name the projector needs rather than borrowing it from the router.
CapabilityInstaller::__construct()
public function __construct(Milpa\Console\Http\HttpProjector $projector, Psr\Http\Message\ResponseFactoryInterface $responses = new Psr17Factory()):Parameters
| Name | Type | Description |
|---|---|---|
| $projector | Milpa\Console\Http\HttpProjector | |
| $responses | Psr\Http\Message\ResponseFactoryInterface |
CapabilityInstaller::handle()
public function handle(Psr\Http\Message\ServerRequestInterface $request): Psr\Http\Message\ResponseInterfaceRuns the install the panel's button asked for, through the operation's own HTTP ceremony.
Parameters
| Name | Type | Description |
|---|---|---|
| $request | Psr\Http\Message\ServerRequestInterface |