feat(plugin): install the pipelines' skill plugins on SessionStart
The ship-feature pipelines drive `/superpowers:*` commands as their per-node drivers, so a fresh install had a dependency it was only told about — the `/ccam-doctor` WARN row and a line in the README. `server/lib/skill-plugins.js` now carries the whole thing, shared by the doctor (reports) and the bootstrap (installs) so the two cannot disagree about what is missing. The bootstrap installs at the very end of its DETACHED worker — the install clones from the network and nothing in the 10 s SessionStart hook may wait on it — retrying once behind a `marketplace add`, logging a failure with the manual command, and never throwing: the dashboard, hooks, CLI and MCP all work without these plugins. The outcome is recorded as `state.skillPluginsSettled`, which `fastPathOk()` now also requires, so the check runs exactly once per install and `/ccam-update` is the retry. `CCAM_AUTO_INSTALL_PLUGINS=0|false|off` opts out. Reporting is derived, installing is allowlisted. Requirements come from the loaded templates, which is right for a report; installing from that same source would not be, because a template is a file anyone can drop into `DASHBOARD_PIPELINES_DIR` — it would turn "edit a JSON file" into "run this vendor's install command on the next session". Auto-install consults `AUTO_INSTALLABLE`, a constant in code (`superpowers` today), and reports every other requirement as skipped. Tests inject a `run` seam so no case reaches a real `claude plugin install`, and cover the refusal explicitly.
This commit is contained in:
@@ -199,6 +199,39 @@ satisfied, so a hand-copied setup is not reported as broken. A custom template
|
||||
in `DASHBOARD_PIPELINES_DIR` naming some other plugin's command is checked the
|
||||
same way.
|
||||
|
||||
Both the derivation and the missing/satisfied rules live in
|
||||
`server/lib/skill-plugins.js`, shared with the bootstrap below so the row and
|
||||
the install can never disagree about what is missing.
|
||||
|
||||
#### Automatic install, and why it is allowlisted
|
||||
|
||||
`plugin-bootstrap.js` installs the missing plugins itself, at the very end of
|
||||
its **detached worker** — never in the 10 s `SessionStart` hook, because the
|
||||
install clones from the network. It runs `claude plugin install
|
||||
superpowers@claude-plugins-official --scope user -y`; if that fails it registers
|
||||
the marketplace (`claude plugin marketplace add anthropics/claude-plugins-official`)
|
||||
and retries exactly once. Failure is logged with the manual command and nothing
|
||||
throws — the dashboard, hooks, CLI and MCP do not need these plugins.
|
||||
|
||||
The result is recorded as `skillPluginsSettled` in the bootstrap's `state.json`,
|
||||
which is also part of `fastPathOk()`: the check runs **once** per install, then
|
||||
the hot path reads one flag. `/ccam-update` (`--force`) is the retry.
|
||||
`CCAM_AUTO_INSTALL_PLUGINS=0` (or `false`/`off`) turns it off entirely.
|
||||
|
||||
An installed plugin only resolves in the **current** session after
|
||||
`/reload-plugins`; a new session picks it up on its own. The log says so, since
|
||||
the worker is detached and cannot tell the session that started it.
|
||||
|
||||
**Reporting is derived, installing is allowlisted.** The row above reads plugin
|
||||
names out of the templates, which is right for a report. Installing from the
|
||||
same source would not be: a template is a file anyone can drop into
|
||||
`DASHBOARD_PIPELINES_DIR`, so it would turn "edit a JSON file" into "run this
|
||||
vendor's plugin install command on the next session". Auto-install therefore
|
||||
consults `AUTO_INSTALLABLE`, a fixed map in `server/lib/skill-plugins.js`, and
|
||||
skips every other requirement — visible in the doctor, never installed. Adding
|
||||
an entry there is a decision to install someone else's code on a user's machine
|
||||
without asking; it belongs in a review, not in a config file.
|
||||
|
||||
### Where things live
|
||||
|
||||
| Thing | Location | Survives a plugin update |
|
||||
|
||||
Reference in New Issue
Block a user