quillkit
v0.5.1
Published
The quill author's toolchain: gate a quiver, pack it, look at it, ship it. Carries the studio client it serves.
Downloads
598
Maintainers
Readme
quillkit
The quill author's toolchain: one command over the whole loop. Gate a quiver, pack it, look at it, ship it.
Install
npm install --save-dev quillkit @quillmark/quiver @quillmark/wasmquillkit carries neither of the other two. It resolves both out of your collection's own node_modules, so the versions you pin are the format your quiver is packed in and the wasm your gate renders through. The studio client is the one thing it does carry: studio and site serve it out of the tool's own dist/client, so there is nothing to install for it and nothing to keep in step.
That client compiles in its own copies of both libraries and the engine, which your install does not resolve and your lockfile does not record. dist/client/carried.json names all three, and each release's notes say the same in one line.
The verbs
| Verb | What it does |
| ----------------- | ------------------------------------------------------------------ |
| quillkit test | the gate: every quill's example document compiles and renders |
| quillkit build | pack the source layout into a servable artifact |
| quillkit studio | the local loop: pack, serve, repack on save |
| quillkit site | the deploy layout: the client at a root, a built quiver beneath it |
Every verb takes --quiver <dir>, the collection root where Quiver.yaml lives, defaulting to the working directory. build, studio and site take --out <dir>, and studio takes --port <n> and --host <addr>.
Gating
test is what you are blocked on: it runs in CI, against your own wasm, and installs no app.
// package.json
{
"scripts": { "test": "quillkit test" }
}It loads the source layout with fromDir, then compiles and renders every quill's example document, seeded from the blueprint's example: values. It finds the engine itself: a named engine export from quillkit.config.js at the collection root, else @quillmark/wasm from your own node_modules.
On vitest, jest or node:test, spawn the bin rather than rebuilding the loop against the library. The gate stays one implementation, and the case gates what CI gates:
import { execFileSync } from 'node:child_process';
it('gates the quiver', () => {
execFileSync('quillkit', ['test'], { stdio: 'inherit' });
});Looking at it
studio is what you look at: it packs your source, serves the studio client over it, and repacks whenever you save. Nothing fails a build on its verdict.
npx quillkit studioPick a quill, edit, watch it paint, read the errors. quillkit test answers does it work; studio answers what is it like to use. The document it holds is the blueprint's own, so what the gate renders is what you judge. Reload the page to pick up a repack.
It shows a quill rather than editing one: no plate editing, no schema editing, no auth, and nothing it holds outlives the tab.
The client renders through the @quillmark/wasm it was built against, and the head names it; your quillkit test runs whatever your own tree holds, and nothing at runtime reconciles the two. The gate is authoritative, studio is advisory.
Shipping it
site writes the arrangement a deploy serves (the client at the root, a built quiver at quiver/ beneath it, which is where the client looks) and asserts both halves of it.
npx quillkit site --out ./siteThe client resolves its quiver against document.baseURI and its assets relatively, so any static host works and no rebuild is needed per URL. The arrangement itself is two rules: the client's files at some base with a built quiver at quiver/ under that same base, and no quiver inside the client, since one packed there would occupy the URL the built one is served from.
For GitHub Pages, the build is quillkit site and an artifact upload:
# .github/workflows/studio.yml
name: Studio
on:
push:
branches: [main]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
cache: npm
- run: npm ci
- run: npx quillkit site --out site
- uses: actions/upload-pages-artifact@v3
with:
path: site
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4Keep the deploy in your own repository, as above: nothing outside it then holds pages: write.
If your quiver is not an npm project (a Quiver.yaml and quills/ with no package.json), there is no tree for the packer to be resolved from, so install it for the run and drop the npm ci:
- run: npm install --no-save @quillmark/quiver quillkit
- run: npx quillkit site --out siteThat takes whatever @quillmark/quiver is current, where a package.json would pin the format your quiver is packed in. site packs files and instantiates nothing, so either way the deploy installs no wasm.
A deployed quiver is frozen at a commit, so the repack loop is the local one, over a working tree.
Refusals
build and site clear what they write, so an --out that is, or contains, your collection or the working directory is refused rather than deleted. build assembles each generation beside its output and moves it in whole, so a client reading mid-pack sees the previous one and a failed pack leaves it serving.
