Commit Graph

9 Commits

Author SHA1 Message Date
Maurice 1cabbec11a ci(plugin-sdk): publish on Node 22; skip the dev-db bind test without node:sqlite 2026-07-04 21:36:08 +02:00
Maurice 6ae47cbdf5 fix(plugin-sdk): dev db binds an args array like the real host, and a failed onLoad stops the routes 2026-07-04 20:21:06 +02:00
Maurice 91217e83fa fix(plugins): tolerate a UTF-8 BOM in trek-plugin.json
Windows editors love to prepend a BOM, and a bare JSON.parse then dies
with an "Unexpected token" pointing at an invisible character - in the
SDK CLIs (dev/validate/entry/submit) and, worse, server-side: a BOM in
an author repo travels through pack into the artifact and fails
discovery and registry install. Strip it at every manifest/JSON read
(readJsonFile in the SDK, parseJsonText in the installer).
2026-07-04 20:21:06 +02:00
Maurice d110f8f0ce fix(plugin-sdk): make require('trek-plugin-sdk') actually resolve everywhere
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
2026-07-04 20:21:06 +02:00
Maurice cf9be554ac feat(plugin-sdk): dev server, preflight, auto-PR submit, signing, wizard
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).
2026-07-04 19:11:23 +02:00
Maurice c3c70bcf9d feat(plugin-sdk): one-command publishing — pack, entry, release
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.
2026-07-04 19:11:23 +02:00
mauriceboe 17f3c86967 feat(plugins): hero widget slot + Koffi reference plugin
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).
2026-07-04 19:11:23 +02:00
mauriceboe 1cee4e93b1 feat(plugins): lifecycle polish — uninstall, error log, egress guard, widget slot (M8)
- 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.
2026-07-04 19:11:23 +02:00
mauriceboe af73943be8 feat(plugins): trek-plugin-sdk package — types, mock host, scaffolder, validator (M6)
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.
2026-07-04 19:11:23 +02:00