Testing and publishing
The kryton-plugins
repository is the development workspace for every official plugin and
the staging area for community submissions. It ships with a build,
test, and validate workflow you can lean on.
Test runner
Section titled “Test runner”vitest is the runner — it’s declared in
kryton-plugins/package.json:
"devDependencies": { "esbuild": "^0.25.0", "jsdom": "^25.0.0", "typescript": "^5.9.0", "vitest": "^2.1.0"}Convention: each plugin keeps its tests inside its own
__tests__/ folder, alongside manifest.json. Examples:
plugins/checklist/__tests__/parser.test.jsplugins/kanban/__tests__/board-model.test.jsplugins/flashcards/__tests__/srs.test.jsplugins/advanced-tables/__tests__/format.test.js
A vitest example
Section titled “A vitest example”From plugins/checklist/__tests__/parser.test.js:
import { describe, it, expect } from 'vitest';const { extractCheckboxes } = require('../parser.js');
describe('extractCheckboxes', () => { it('returns empty for note with no checkboxes', () => { expect(extractCheckboxes('plain text', 'a.md')).toEqual([]); }); it('parses unchecked and checked items', () => { const md = '- [ ] todo\n- [x] done\n - [X] indented'; expect(extractCheckboxes(md, 'n.md')).toEqual([ { path: 'n.md', line: 1, checked: false, text: 'todo' }, { path: 'n.md', line: 2, checked: true, text: 'done' }, { path: 'n.md', line: 3, checked: true, text: 'indented' }, ]); });});The pattern across the repo: extract pure logic (parsers, model transforms, formatters) into a plain module the test imports directly, then drive UI from that module. Don’t test through the host — there’s no host in vitest.
Repo scripts
Section titled “Repo scripts”From kryton-plugins/package.json:
| Script | What it runs |
|---|---|
npm run build | node scripts/build-plugins.js — esbuild bundles each plugin’s TypeScript to JS. |
npm run validate | node scripts/validate-registry.js — manifest sanity checks (see below). |
npm run generate | node scripts/generate-registry.js — rebuilds registry.json from manifests. |
npm test | node scripts/test-plugins.js && vitest run — per-plugin sanity tests, then the vitest suite. |
npm run test:unit | vitest run — just the vitest suite. |
npm run test:watch | vitest — watch mode for local dev. |
npm run typecheck | tsc --noEmit. |
npm run lint | eslint plugins/ --ext .js. |
Manifest validation
Section titled “Manifest validation”scripts/validate-registry.js enforces:
- Each plugin folder has a parseable
manifest.json. - Required fields are present:
id,name,version,description,author,minKrytonVersion. manifest.idmatches the directory name.- Declared entry points (
server,client) exist on disk. - Settings entries are well-formed.
- No two plugins share an id across the repo.
The script exits non-zero if any check fails; CI runs it on every PR.
Publishing to the registry
Section titled “Publishing to the registry”registry.json is auto-generated — generate-registry.js reads
every plugins/*/manifest.json and rewrites the file. Don’t edit it
by hand.
Workflow for a new community plugin:
- Fork
kryton-plugins. - Create
plugins/<your-id>/with the layout from the overview. - Locally:
npm install && npm run validate && npm test && npm run build. - Run
npm run generatesoregistry.jsonreflects your plugin. - Open a PR. CI re-runs validate, test, and build; reviewers check the
plugin against the contribution guidelines in
kryton-plugins/README.md.
Once merged, your plugin shows up in every Kryton instance’s Plugin Manager on the next registry refresh.
Local installation (no registry)
Section titled “Local installation (no registry)”For development or private plugins you don’t want to publish: drop the folder into the running Kryton’s configured plugins directory, then reload from the admin panel. The lifecycle is exactly the same as a registry install — see Overview → Lifecycle.