plugin

package
v0.1.0-rc.63 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package plugin wires `w17ctl plugin <leaf>` — the plugin catalogue commands (list / install / update / gen-pb). The catalogue is SERVED BY THE CONSOLE (ListPluginCatalog / FetchPlugin); the client carries no copy, so a plugin change reaches a consumer through a console deploy rather than through a client release. This package owns the install/update logic and nothing else.

Index

Constants

View Source
const DefaultPluginsRepo = "https://github.com/wandering-compiler/plugins"

DefaultPluginsRepo is where a bare plugin NAME resolves to.

`w17ctl plugin install auth` is sugar for the organisation's own registry — the same mechanism as any other repository, with the URL filled in. It is a client-side default, like the compile-time console address, and not a rule about plugins: pointing it elsewhere with W17_PLUGINS_REPO changes which registry "by name" means, and spelling the repository out always wins.

The console used to answer this question by SERVING the plugin's bytes from a catalogue compiled into it. That made the console a file server for plugins and a second source of truth beside the registry, which is what this replaced.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cmd

type Cmd struct {
	List    ListCmd    `cmd:"" help:"List the console's plugin catalogue + each plugin's install state in this project's lock."`
	Install InstallCmd `` /* 324-byte string literal not displayed */
	Update  UpdateCmd  `` /* 298-byte string literal not displayed */
	GenPb   GenPbCmd   `` /* 145-byte string literal not displayed */
	Dev     DevCmd     `` /* 374-byte string literal not displayed */
	Render  RenderCmd  `` /* 332-byte string literal not displayed */
	Sign    SignCmd    `` /* 284-byte string literal not displayed */
}

Cmd is the parent of `w17ctl plugin <leaf>` commands:

  • `list` — inventory of the console's catalogue + installed plugins
  • `install` — fetch one plugin into the project's `<proto_dir>/plugins/` tree + record it in the lock. Two sources: a NAME, served from the console's catalogue, or a RELEASE in a repository, spelled `<repo>#<plugin>/<version>`. The fragment is the git tag itself, so what an operator types is what the repository carries. A repository install also records the commit that tag resolved to and the digest of the tree that landed, so the lock pins which BYTES were installed and not only which version number
  • `update` — re-fetch one (or every) installed plugin from the console's catalogue, refreshing the on-disk tree + the lock version

`remove` is a v2 feature; until then operators manually `rm -rf <proto_dir>/plugins/<name>/` + drop the lock entry.

type DevCmd

type DevCmd struct {
	Dir string `` /* 126-byte string literal not displayed */

	Features    string `` /* 160-byte string literal not displayed */
	AllFeatures bool   `` /* 247-byte string literal not displayed */

	Out     string `` /* 313-byte string literal not displayed */
	Keep    bool   `` /* 128-byte string literal not displayed */
	Console string `` /* 207-byte string literal not displayed */
	Org     string `` /* 128-byte string literal not displayed */

	SignInFrom string `` /* 220-byte string literal not displayed */
}

DevCmd runs a plugin AS ITSELF: it stands up a throwaway w17 project, turns this plugin on in it, and generates.

Why a plugin needed this

A plugin's unit tests exercise its handlers over doubles, and they do it well. What they cannot exercise is the half a plugin IS: the proto producing a storage tier, the handlers being STAGED with their import paths rewritten, the bundle compiling, the surface answering. None of that exists inside `plugins/<name>/` — it is created by ACTIVATION in a project — so there is nothing there to integrate against, and a plugin module is forbidden from depending on anything project-shaped anyway (a repo-relative `replace` is refused, because the module is vendored into a tree where that path does not exist).

Measured before building this: of four shipped plugins, two had never been activated by anything — never generated, never staged, never compiled in a project, never called. Their handlers had 124 test functions between them.

Why not an example project per plugin

That was the first plan and this is better in the way that matters: it goes through `install` and `codegen`, which is the path a CONSUMER takes. An authored example tests a tree we wrote; this tests the tree they receive. It also works for an author who has no monorepo, the feature matrix is a flag rather than N copies of a project, and there is no per-plugin hand-written scaffolding to drift.

What it does NOT prove

That the surface answers. This stops at codegen, which is where a plugin that has never been generated fails — and the live half needs a stack, a database and a console. `--up` is where that goes, and until it exists this command says "it generates", not "it works".

func (*DevCmd) Run

func (c *DevCmd) Run() error

type GenPbCmd

type GenPbCmd struct {
	Dir     string `` /* 137-byte string literal not displayed */
	Console string `` /* 175-byte string literal not displayed */
}

GenPbCmd implements `w17ctl plugin gen-pb [dir]`.

It regenerates a plugin's standalone `src/gen/pb/*.pb.go` from its `proto/` tree — the committed pb files that exist ONLY for the plugin author's local dev/test loop (`go test ./...` inside `src/`). The project codegen pipeline generates its OWN per-activation pb at staging time and never uses these files.

Thin-client model: the compile is a COMPILER concern, so it runs on the console. The client only uploads the raw proto/ tree + plugin.yaml to the GeneratePluginPb RPC, and writes the pb.go files the server returns — no buf / loader / manifest / placeholder logic client-side.

func (*GenPbCmd) Run

func (c *GenPbCmd) Run() error

type InstallCmd

type InstallCmd struct {
	Source  string `` /* 130-byte string literal not displayed */
	Console string `` /* 214-byte string literal not displayed */
}

InstallCmd implements `w17ctl plugin install <name|url>`.

v1 supports name-only — the named plugin must exist in the console's catalogue. URLs are accepted at the argument layer to reserve the surface for v2 but rejected at the handler with a steering message.

Install:

  1. Resolve the project root + lock.
  2. Refuse if `<name>` is already in lock.plugins[], or if `<root>/<proto_dir>/plugins/<name>/` already exists — v1 has no `remove`, so the operator cleans up first. Both are local checks and run BEFORE the console is dialled: a repeat install should not stream a plugin tree only to refuse it.
  3. Stream the plugin from the console into a sibling STAGING dir.
  4. Validate the staged plugin.yaml server-side (InspectPluginManifest): manifest errors, name/dir disagreement, requirement warnings.
  5. Append `PluginInstall{name, version, source: "internal"}` to the lock via EditLock (the server appends + re-signs).
  6. Only then rename the staged tree into place.

func (*InstallCmd) Run

func (c *InstallCmd) Run() error

type ListCmd

type ListCmd struct {
	LockPath string `name:"lock" placeholder:"PATH" default:"w17/lock.yaml" help:"Path to the lock file."`
	Console  string `` /* 189-byte string literal not displayed */
}

ListCmd implements `w17ctl plugin list`. Asks the console for its plugin catalogue and cross-references the lock's `plugins[]` to surface install state. One line per plugin; reports "no plugins available" when the console serves none and the lock records none.

func (*ListCmd) Run

func (c *ListCmd) Run() error

type RenderCmd

type RenderCmd struct {
	Dir string `` /* 173-byte string literal not displayed */
	Out string `` /* 190-byte string literal not displayed */

	Catalogue bool     `` /* 231-byte string literal not displayed */
	Notes     []string `` /* 233-byte string literal not displayed */
}

RenderCmd turns an author tree into the PUBLISHED form a registry serves.

The step between writing a plugin and releasing it, and the one an external author had no way to run: it lived as a shell loop in this repository's Makefile, which somebody outside the team does not have. `sign` and `gen-pb` were already here; this is the piece that was missing between them.

⚠️ It renders, and nothing else. No git, no remote, no tag — so it is safe to run over and over while writing a plugin, and it is what `plugin dev` uses to install the tree the way a CONSUMER will receive it rather than the way the author happens to have it on disk. Those differ: the Go goes inert and the tests come along, and installing the author's tree directly would test bytes nobody is ever served.

func (*RenderCmd) Run

func (c *RenderCmd) Run() error

type SignCmd

type SignCmd struct {
	Dir     string `arg:"" name:"dir" help:"Plugin tree to sign — the directory holding plugin.yaml."`
	Console string `` /* 210-byte string literal not displayed */
	Print   bool   `` /* 143-byte string literal not displayed */
}

SignCmd signs a plugin tree for release: the publish-side half of the check `plugin install` runs.

It writes `plugin.sig` beside the manifest and nothing else. Publishing the tree, tagging it and pushing it stay where they already are (scripts/publish-plugins.sh) — this command's whole job is to turn a directory into a signed directory, so it can be run on a mirror, on a checkout, or in CI without any of them needing to know how signing works.

⚠️ THE KEY IS NOT HERE. The digest is computed locally (hashing is not trust cryptography, and `plugindigest` is in the public SDK precisely so the publisher and every consumer get the same answer); the signature comes from the console. Public-split §4 — the same rule that put VerifyLock there, and the reason `w17ctl` can be handed to plugin authors at all.

func (*SignCmd) Run

func (c *SignCmd) Run() error

type UpdateCmd

type UpdateCmd struct {
	Name    string `arg:"" optional:"" name:"name" help:"Installed plugin to refresh. Mutually exclusive with --all."`
	All     bool   `name:"all" help:"Update every plugin recorded in lock.plugins[]."`
	To      string `` /* 238-byte string literal not displayed */
	From    string `` /* 269-byte string literal not displayed */
	Console string `` /* 214-byte string literal not displayed */
}

UpdateCmd implements `w17ctl plugin update <name>` and `w17ctl plugin update --all`. Both branches share the same per-plugin logic; --all just iterates over every installed plugin in the lock.

Per-plugin update:

  1. Lock entry must exist for `<name>` (otherwise the operator wants `plugin install` instead).
  2. The console's catalogue must carry `<name>` (URL-installed plugins can't be updated through this path).
  3. The fetched manifest is validated server-side; CheckRequires runs against the running w17 version.
  4. The refreshed tree is staged, then swapped in. The manifest's `version` becomes the new `lock.plugins[].version`.
  5. Lock is re-signed once at the end (one save per command run regardless of how many plugins update).

func (*UpdateCmd) Run

func (c *UpdateCmd) Run() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL