standard-plugin-sdk 0.1.2

Write Standard Code plugins in Rust: wasm components against standard:plugin@2.0.0
Documentation
# Store previews and icons

The plugin store shows each plugin's page with a live preview: your plugin's
real UI half, run by the viewer in a sandbox, drawing every surface it
declares on a strip of tiles. A large surface (a stage, a pane, a column, a
popover) can be expanded to the size of the store's window. The person
browsing can click a tile and use it with the keyboard and pointer before
installing.

What the store does without any work from you:

- It shows each surface your manifest declares, at the size the store gives
  it, and sends the plugin the usual `resize` and `visibility` events.
- It runs each command whose `opens` names a surface that must be opened
  (a stage, a popover, a pane or a column), so the surface starts as it
  would when a person opens it. Give every such command an `opens`.
- For a surface the viewer makes one of per pane, machine or project
  (`pane.footer`, `machine.after`, `project.after`, ...), it shows one
  instance, for the first pane, machine or project of a sample account.

What the sandbox gives your plugin: a sample account of two machines, two
projects and three panes (one agent working, one waiting); values,
secrets, claims and configuration that start empty and vanish with the
preview; calls that answer `unavailable` (your daemon half never runs);
and no URL opener. When your manifest asks for `events.on:system.agents.*`,
an agent pane finishes or starts a turn every few seconds.

## Your plugin's part: its own preview state

A plugin whose surfaces show data from its daemon, a service or the
account would show only "Loading…" or "No data" in that sandbox. **Each
plugin is responsible for a preview that shows what it really looks like,
and for keeping it current as the plugin changes.**

The store sets the value `<your id>.standard-preview` to `true` before your
plugin activates. It is in your own namespace, so reading it needs no
grant. When it is true:

1. Build your state from sample data instead of reading it: realistic
   values that show every part of every surface (a full card, a warning
   state, a long name that truncates).
2. Make no calls and start no requests: they answer `unavailable`.
3. Keep animating as usual, so the preview moves as the plugin does.

```rust
const PREVIEW: &str = "my-plugin.standard-preview";

fn activate(&mut self, cx: &mut Context) {
    let preview = cx.values().get::<bool>(PREVIEW).ok().flatten() == Some(true);
    if preview {
        self.state = State::sample();
        return;
    }
    // ... the real start: read values, call the daemon, watch the account
}
```

Keep `State::sample()` beside your real state and update it in the same
change as any new field or surface, so the preview never falls behind. A
unit test that activates the plugin with the preview value set and checks
that it paints without a call is the cheapest way to keep it honest:

```rust
let mut host = MockHost::new("my-plugin");
host.values.insert("my-plugin.standard-preview".into(), "true".into());
```

The preview is still your plugin's real code drawing: only the data is
yours to choose. Show what a person will see, not a better version of it.

## Your plugin's icon

The store shows an icon beside your plugin's name, drawn by terminals that
support Kitty graphics (others show a tile with your plugin's initials).
For a first-party plugin, put a square 256Ă—256 PNG of at most 64 KiB in the
plugin's directory as `icon.png`: the release carries it in the package's
metadata and the registry serves it to the store. Make it show what your
plugin draws, readable at 32 px, with no text.