# Contributing The plugin is plain JavaScript on both halves: no build step, no transpiler. The host half (`lib/`) runs in Node, the client half (`lib/client.js`) runs in the app's web shell, and the shell scripts it drives inside the distribution are generated from templates in `lib/scripts.js`. ## The checks One command runs everything: ```sh npm run check # every check, in one sequence npm run check:offline # only the checks that need no distribution ``` It prints one line per check, and a check that cannot run on this machine is reported as skipped with the reason. Nothing passes silently. The checks that drive a browser — `check-assets.mjs`, `check-ui.mjs` and `capture-panel.mjs` — speak Chrome's debugging protocol over a WebSocket, so they need Node 22 or newer. On an older Node `check-all.mjs` runs everything else and reports them skipped with that reason. The checks, and what each one needs: ```sh node scripts/check-manifest.mjs # manifest, exports, package contents (Node) node scripts/check-client.mjs # the client half (Node) node scripts/check-theme-tokens.mjs # the theme tokens (Node) node scripts/check-assets.mjs # the readme images render, per theme (browser) node scripts/check-bash.mjs # the generated shell scripts (Node, bash when reachable) node scripts/check-pack.mjs # the tarball installs and starts (Node, a profile) node scripts/check-projects.mjs # two projects, one port each (distribution) node scripts/check-urls.mjs # every link answers (distribution) node scripts/check-legacy.mjs # a unit from an older version (distribution) node scripts/check-shared-home.mjs # the home decides the project (distribution) node scripts/check-alias.mjs # the name store (distribution) node scripts/check-ui.mjs # a browser shows the correct project (browser) node scripts/check-readme.mjs # every claim in the readme (distribution) node scripts/check-all.mjs # all of the above in one sequence (whatever is present) ``` `check-pack.mjs` packs the plugin, installs that tarball into a profile it makes from a copy of yours, starts a server on it, and asks that server for the plugin's route. A file left out of `files`, an export that does not resolve, or a manifest that installs but does not load are all invisible from the checkout and visible here. Without a profile it checks the tarball contents and says so. `check-assets.mjs` keeps the readme's images honest: it reads the `` blocks out of the readme, loads every file they name in a real browser, and measures what each renders as. The dark variant has to be darker than the light one, and a narrow SVG has to follow the colour scheme from inside its own `