A freshly scaffolded plugin could not load anywhere: the npm package is
ESM-only (no require condition in its exports map), so the scaffold's
require('trek-plugin-sdk') threw ERR_PACKAGE_PATH_NOT_EXPORTED under
`trek-plugin dev` - and the runtime injection the wiki promised for the
plugin child never existed, so a packed plugin (node_modules stripped)
crashed with MODULE_NOT_FOUND after a real install.
- plugin child: inject a frozen {definePlugin, PLUGIN_API_VERSION} shim
for require('trek-plugin-sdk'); subpaths fail with a pointed error
- trek-plugin dev: inject the exact same shim, so a fresh scaffold runs
with zero npm install and dev parity with production holds
- npm package: ship a real CommonJS build (dist/cjs + require export
conditions) so the installed package also requires cleanly on Node 18+
- create: scaffold a package.json (type commonjs, SDK as devDependency,
npx scripts); print resolvable `npx trek-plugin-sdk ...` hints
- wiki: package.json in the scaffold tree + publishing checklist, and
document the zero-install dev flow
Round out the author experience so the loop is create -> dev -> release/submit
without hand-work or a round-trip through registry review.
- `dev`: run a plugin locally with a real request loop and hot reload — no full
TREK. Injects a ctx that enforces the manifest's granted permissions (an
ungranted call throws, so you catch a missing grant), backs db:own with a real
SQLite file (node:sqlite), serves routes under /api and page/widget UI at /ui,
and reloads on save. Dependency-free (node:http + built-ins).
- `preflight`: run the registry CI checks locally over the network (tag->commit,
manifest parity, artifact sha256/size, native scan, README quality gate) so a
green run predicts a green CI.
- `submit`: fork TREK-Plugins, branch off current main, write/merge the entry,
push, and open the PR — the last manual publishing step, automated.
- `keygen`/`sign` + `--sign` on entry/release/submit: dependency-free Ed25519
author signatures over the artifact bytes, verified 1:1 against the server's
TOFU check. Fills authorPublicKey + signature and guards against a key change.
- `create` gains an interactive wizard (id/type/author/permissions) and flags.
- README + Development/Publishing/Permissions wikis document the new flow.
24 tests pass (sign round-trips through a server-shaped verifier; zip reader;
scaffold options; entry signing + key-change guard).
Publishing a plugin meant hand-building the zip, running shasum + stat,
resolving the tag's commit, and hand-writing the whole registry entry.
The SDK does all of it now:
- `trek-plugin pack` builds plugin.zip in the exact layout the installer
reads (own tiny zip writer, so the SDK stays dependency-free and the
format can't drift from the reader), enforces the same native-binary and
size rules, and prints the sha256 + size. docs/ is left out — the store
fetches the screenshot from the repo, so it doesn't belong in the install
artifact (Koffi's went from 943 KB to 15 KB).
- `trek-plugin entry` emits the ready-to-PR registry entry from the manifest
+ the packed zip + the git tag: commitSha (deref'd), downloadUrl, sha256,
size, and minTrekVersion derived from the manifest's trek range. `--merge`
prepends a new version onto an existing entry for updates.
- `trek-plugin release` chains pack → gh release → entry.
Also: the scaffold now points the README at docs/screenshot.png (the path
the store actually fetches, was screenshot-1.png) with a size hint, and
stops hard-coding an MIT license — a plugin is the author's own code under
their own license. Round-tripped against the real server extractor; 18 tests.
Widget plugins can now declare capabilities.widget.slot 'hero' to render as a
transparent, click-through overlay sitting on the boarding-pass bar's top edge
(migration 157 persists capabilities; manifest validation server+SDK, feed
exposes the slot, dashboard mounts hero frames above the pass). Sidebar stays
the default slot.
Replaces the trip-countdown example with Koffi, the TREK mascot: an animated
suitcase with a 14-state behavior engine driven by real trip data — walking,
waving, napping, trolley rolls, passport-stamp stickers, a split-flap luggage-
tag countdown under 7 days, and sunglasses while the trip runs. Validated by
the SDK suite like any author plugin; published as mauriceboe/trek-plugin-koffi
in the registry.
Migrations 156/157 follow the idempotent ALTER pattern (the reconciliation
test re-runs everything from v135, so duplicate-column must stay non-fatal).
- Uninstall with data disposition: POST /api/admin/plugins/:id/uninstall kills the
plugin, removes its code + DB metadata, and (deleteData) drops its data dir,
error log and per-user settings.
- Error log: GET/DELETE /api/admin/plugins/:id/errors — the plugin's own crash /
request-failure log, surfaced in the admin panel.
- Egress guard: the isolated child wraps global fetch and refuses any outbound
host not in the plugin's declared egress[]; with none declared, all outbound is
blocked. Process-level defense in depth (the container runtime enforces it at
the network layer in v2).
- Admin → Plugins is now actionable: activate / deactivate / uninstall, a
registry browser (install), and per-plugin error log. i18n across all locales.
- Dashboard widget slot: active widget plugins render as sandboxed cards.
The trek:request core-data bridge + photo/calendar hook consumers remain follow-ups.
The author-facing SDK, a standalone dependency-free package (not wired into the
app workspaces, so it can't affect the app build).
- definePlugin + the full plugin type surface (PluginContext, PluginRoute,
PluginJob, PhotoProvider, CalendarSource) mirroring what the isolated runtime
injects; PLUGIN_API_VERSION.
- createMockHost (trek-plugin-sdk/testing): a PluginContext that enforces the
SAME permission model + membership checks, so authors can unit-test that their
plugin degrades gracefully — no running TREK needed.
- validateManifest: the exact rules the registry CI runs, so a local pass
predicts a CI pass.
- CLIs: create-trek-plugin (scaffolds a working plugin + README + starter iframe)
and trek-plugin validate (manifest + README sanity).
Consolidating the server loader to import this shared validator is a follow-up.