mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-12 12:28:32 +00:00
86 lines
4.9 KiB
Markdown
86 lines
4.9 KiB
Markdown
---
|
|
name: plugin-scaffold
|
|
description: Scaffold a Slopsmith plugin skeleton with capability-pipelines metadata. USE WHEN the user asks to create a new plugin, scaffold a plugin, bootstrap a plugin, new visualization plugin, new overlay plugin, new settings-only plugin, plugin starter, plugin skeleton. Args needed - plugin slug (snake_case) and type (visualization / overlay / settings-only / routes-only). Generates plugins/<id>/ with plugin.json, capability-pipelines metadata, screen.js, and optional routes.py / settings.html / Playwright test stub matching the requested type.
|
|
---
|
|
|
|
# plugin-scaffold
|
|
|
|
Generates a minimum-viable Slopsmith plugin skeleton matching a requested shape. The output validates against [`schema/plugin.schema.json`](../../../schema/plugin.schema.json).
|
|
|
|
## When to invoke
|
|
|
|
The user says one of:
|
|
- "scaffold a new plugin called X"
|
|
- "create a visualization plugin"
|
|
- "new overlay plugin"
|
|
- "plugin starter for settings"
|
|
- "bootstrap a routes-only plugin"
|
|
|
|
If the plugin slug or type is missing, ask once.
|
|
|
|
## Inputs
|
|
|
|
| Arg | Required | Values | Notes |
|
|
|---|---|---|---|
|
|
| `id` | yes | snake_case | Becomes plugin's `id` field and directory name |
|
|
| `name` | optional | string | Defaults to title-case of `id` |
|
|
| `type` | yes | `visualization` / `overlay` / `settings-only` / `routes-only` | Determines which files get scaffolded |
|
|
|
|
## What to generate
|
|
|
|
**Common to all types:**
|
|
|
|
- `plugins/<id>/plugin.json` — schema-valid manifest. Set `id`, `name`, `version: "0.1.0"`, `license: "AGPL-3.0-only"`, and `standards: ["capability-pipelines.v1", "plugin-runtime-idempotent.v1"]` by default (ask if a different license is desired).
|
|
|
|
**`type=visualization`** — adds:
|
|
- `"type": "visualization"` and `"script": "screen.js"` to manifest
|
|
- `"capabilities": { "visualization": { "roles": ["provider"], "operations": ["renderer.create", "renderer.destroy", "renderer.inspect"], "mode": "active", "compatibility": "none", "ownership": "multi-provider", "safety": "safe", "version": 1 } }`
|
|
- `screen.js` exporting `window.slopsmithViz_<id> = function () { return { contextType: '2d', init(canvas, bundle) { this.ctx = canvas.getContext('2d'); }, draw(bundle) { /* TODO */ }, destroy() {} }; };` plus a static `matchesArrangement` example commented out
|
|
- `tests/browser/<id>.spec.ts` — Playwright stub that loads the app and asserts the plugin's factory is registered
|
|
|
|
**`type=overlay`** — adds:
|
|
- `"script": "screen.js"` to manifest (no `type` declared — overlays don't use the picker)
|
|
- `"capabilities": { "ui.player-overlays": { "roles": ["provider"], "mode": "active", "compatibility": "none", "ownership": "multi-provider", "safety": "safe", "version": 1 } }`
|
|
- a matching `"ui"` contribution with a stable overlay id and redaction-safe label
|
|
- `screen.js` scaffolding an own-canvas + own-rAF loop for the declared overlay contribution, and respecting renderer ownership if it uses highway geometry helpers
|
|
- `tests/browser/<id>.spec.ts` — toggle on / off test
|
|
|
|
**`type=settings-only`** — adds:
|
|
- `"settings": { "html": "settings.html" }` to manifest
|
|
- `"settings_schema"` with a schema version and an empty `packable_keys` list
|
|
- a `"ui"` settings contribution with a stable id
|
|
- `settings.html` — empty form skeleton with explanatory comments
|
|
- `screen.js` reading/writing `localStorage` keys prefixed with `<id>_`
|
|
|
|
**`type=routes-only`** — adds:
|
|
- `"routes": "routes.py"` to manifest
|
|
- a conservative `"capabilities"` declaration for the route's Slopsmith-facing workflow; if the domain is unclear, ask what capability domain the route owns, provides, requests, or observes before finalizing the scaffold
|
|
- `routes.py` with `def setup(app, context):` that registers one example route and uses `context["log"].info("plugin ready")` (never `print()`)
|
|
- `tests/test_<id>_routes.py` — FastAPI TestClient stub
|
|
|
|
## After scaffolding
|
|
|
|
Run validation locally:
|
|
|
|
```bash
|
|
python -c "import json,jsonschema; s=json.load(open('schema/plugin.schema.json')); jsonschema.validate(json.load(open('plugins/<id>/plugin.json')), s); print('OK')"
|
|
```
|
|
|
|
Then point the user at [`docs/PLUGIN_AUTHORING.md`](../../../docs/PLUGIN_AUTHORING.md) and the relevant contract doc for the type they chose.
|
|
|
|
## Don'ts
|
|
|
|
- Don't invent plugin-local manifest conventions. If the user wants something custom, either express it through existing `capability-pipelines.v1` metadata or ask whether it should become a real schema field.
|
|
- Don't scaffold a `requirements.txt` without confirming the deps. The plugin loader installs them on first load; an accidental dep slows everyone's startup.
|
|
- Don't pre-fill `localStorage` keys without a prefix. Collisions across plugins are real.
|
|
- Don't generate hidden side effects at import time (`screen.js` top level or `routes.py` top level). Keep all wiring inside the IIFE / `setup()`.
|
|
|
|
## Verification
|
|
|
|
The scaffolded plugin should pass:
|
|
|
|
```bash
|
|
pytest tests/test_plugin_schema.py::test_in_tree_manifest_validates -v
|
|
pytest tests/test_plugin_schema.py::test_in_tree_manifest_id_matches_directory -v
|
|
```
|