npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kailua-packages/headless-cli

v0.10.0

Published

CLI (hcms) fuer Schema-/Content-Pull+Push, Environments, Promote, Seed, Typegen und Doku-Pull gegen die Kailua Headless-CMS API.

Readme

@kailua-packages/headless-cli

hcms — schlanke CLI fuer Schema, Content, Environments, Promote, Seed, Types und Doku gegen die Kailua Headless-CMS REST-API (apps/headless). Nutzt intern @kailua-packages/headless-sdk und baut nur auf Node-Bordmitteln (util.parseArgs, node:readline) auf — keine schweren Dependencies.

Verwendung

Im Monorepo via tsx (kein Build noetig):

npm run hcms --workspace=@kailua-packages/headless-cli -- <befehl> [optionen]
# oder direkt
npx tsx packages/headless-cli/src/cli.ts <befehl> [optionen]

Nach npm run build steht das Bin hcms (dist/cli.js) zur Verfuegung.

Authentifizierung & Konfiguration

Alle API-Befehle brauchen eine Basis-URL und ein Token. Die URL kommt aus --url, der Env-Variable HCMS_URL oder der hcms.config.json (siehe unten). Das Token kommt ausschliesslich aus --token oder der Env-Variable HCMS_TOKEN — es gehoert NIE in die Config-Datei und NIE ins Repo:

export HCMS_URL="https://acme.kailua-packages.ch/headless"
export HCMS_TOKEN="hcms_live_xxx"

Benoetigte Token-Scopes je Befehl: read (types/docs/content pull), write+publish (content push, seed), manage (schema pull/push/diff, env list/clone/status, promote, seed).

hcms.config.json

Projektweite Konfiguration im Frontend-Repo (committen erlaubt — enthaelt keine Secrets). Alle Felder optional; Pfade relativ zum Repo-Root:

{
  "url": "https://acme.kailua-packages.ch/headless",
  "environment": "production",
  "schemaDir": "cms/schema",
  "contentDir": "cms/content",
  "typesOut": "cms/types.generated.ts",
  "docsOut": "cms/llms-full.txt"
}

| Feld | Default | Bedeutung | | ------------- | ------------------------ | ------------------------------------------------ | | url | – | Basis-URL der Headless-App (inkl. /headless) | | environment | Default-Env der Org | Standard-Environment fuer alle Befehle (--env uebersteuert) | | schemaDir | cms/schema | Zielordner fuer schema pull/push/diff (auch theme unter <schemaDir>/themes/) | | blocksDir | cms/blocks | Zielordner fuer blocks pull/push/diff | | layoutsDir | cms/layouts | Zielordner fuer layouts pull/push/diff | | contentDir | cms/content | Zielordner fuer content pull/push | | typesOut | cms/types.generated.ts | Zieldatei fuer types generate | | docsOut | cms/llms-full.txt | Zieldatei fuer docs pull |

Aufloesungs-Reihenfolge: CLI-Flag > Env-Variable (HCMS_URL) > hcms.config.json. Token: nur --token > HCMS_TOKEN (bewusst keine Config-Option; ein token-Feld in der Config wird mit Warnung ignoriert). Die Datei wird vom Arbeitsverzeichnis aus aufwaerts gesucht (wie package.json-Lookup); relative Ausgabepfade aus der Config sind relativ zum Verzeichnis der Config-Datei.

Befehls-Uebersicht

| Befehl | Zweck | | --- | --- | | hcms init [dir] [--url] [--token] [--skip-install] | Frontend-Starter scaffolden (Template + .env.local + docs pull + types generate) | | hcms docs pull [--out] | Per-Org-LLM-Doku (llms-full.txt) als Datei ins Repo laden | | hcms types generate [--out] [--env] [--watch] [--interval 5] [--scaffold-blocks] [--dir components/blocks] | TypeScript-Typen aus Collection-Schema und Bloecken generieren (optional Block-Komponenten scaffolden) | | hcms schema pull [--env] [--out <dir>] | Schema als Dateien ziehen (manifest.json + collections/*.json + components/*.json) | | hcms schema push [--env] [--dry-run] | Schema-Dateien idempotent pushen (upsert per slug, loescht NIE) | | hcms schema diff [--env] | Lokales Schema gegen ein Environment diffen (Server-Diff via Dry-Run) | | hcms blocks pull [--env] [--out <dir>] | Block-Definitionen (DB, source!=code) als hcms/block@1-Dateien ziehen (<blocksDir>/<slug>.json) | | hcms blocks push [--env] [--dry-run] | Block-Dateien idempotent pushen (upsert per slug, loescht NIE; Built-in-Slugs → 422) | | hcms blocks diff [--env] | Lokale Bloecke gegen ein Environment diffen (Server-Diff via Dry-Run) | | hcms layouts pull [--env] [--out <dir>] | Layouts als hcms/layout@1-Dateien ziehen (<layoutsDir>/<slug>.json) | | hcms layouts push [--env] [--dry-run] | Layout-Dateien pushen (Baum-Validierung gegen Ziel-Env; unbekannte Block-Typen → 422) | | hcms layouts diff [--env] | Lokale Layouts gegen ein Environment diffen | | hcms theme pull [--env] [--out <dir>] | Theme-Tokens als hcms/theme@1-Dateien ziehen (<schemaDir>/themes/<slug>.json) | | hcms theme push [--env] [--dry-run] | Theme-Dateien pushen (upsert per name) | | hcms theme diff [--env] | Lokale Themes gegen ein Environment diffen | | hcms content pull --collection X [--env] [--status] [--out] | Eintraege inkl. syncKey als hcms/content@1-Datei ziehen | | hcms content push --collection X [--env] [--file] | Eintraege idempotent pushen (Bulk-Upsert per syncKey+locale, Chunks a 100) | | hcms env list | Environments der Organisation auflisten | | hcms env clone --from <key> --to <key> [--name] [--content] [--pages] [--theme] | Environment in ein NEUES Environment klonen | | hcms env status --op <id> | Status einer Clone-/Promote-Operation abfragen | | hcms promote --from A --to B [--collections a,b] [--with-content] [--pages] [--menus] [--themes] [--conflict overwrite\|skip\|fail] [--dry-run] | Schema (+ optional Content) in ein bestehendes Environment promoten | | hcms seed --template blog [--env] [--file] | Beispiel-Schema + -Content einspielen (idempotent) |

Deprecated-Aliase (Warnung, bleiben uebergangsweise): schema exportschema pull, schema importschema push; content export/content import behalten ihr altes Verhalten (JSON/CSV-Export bzw. reines Anlegen ohne Upsert). Der fruehere migrate-Platzhalter ist zugunsten von schema push und promote entfallen.

Setup & Onboarding

hcms init [dir]

Scaffoldet ein Next.js-Frontend aus dem Starter-Template (templates/frontend-starter im Monorepo bzw. im npm-Paket eingebettet):

  1. Template in den Zielordner kopieren (muss leer/neu sein).
  2. .env.local mit HCMS_URL/HCMS_TOKEN schreiben (Token NIE in die Config).
  3. hcms.config.json im Ziel mit der URL aktualisieren.
  4. npm install (via --skip-install abwaehlbar).
  5. Best-effort docs pull + types generate (Fehler nur als Warnung).

Fehlende --url/--token werden interaktiv erfragt.

hcms init my-site --url https://acme.kailua-packages.ch/headless --token hcms_live_xxx
cd my-site && npm run dev

hcms seed

Spielt ein Seed-Template in fester Reihenfolge ein: Schema → Blocks → Layouts → Content (Blocks vor Layouts, weil der Server den Layout-Baum gegen die Block-Palette des Ziel-Envs validiert). Alle Schritte sind idempotent (Upsert per Slug bzw. per stabilem syncKey — Wiederholung erzeugt keine Duplikate). Relationen im Content referenzieren per "$ref:<syncKey>" und werden von der CLI gegen die zurueckgegebenen Entry-ids aufgeloest.

Eingebaut (--template blog):

  • Collections: author, category, blog
  • Block-Definition: testimonial (Kundenstimme — quote Pflichtfeld, author_name, author_image) als hcms/block@1
  • Layout: landing-page als hcms/layout@1 — verschachtelter Baum section > container > [hero, columns 1:1 [richtext | testimonial], cta] aus Built-in-Bloecken plus dem Seed-Block testimonial
  • Content: 2 Autoren, 3 Kategorien, 5 Blog-Posts

Die Abschnitte blocks/layouts sind optional; ein Template ohne sie seedet nur Schema + Content (abwaertskompatibel). Nach dem Seed sofort einsatzbereit: neue Seite aus dem Layout landing-page anlegen.

hcms seed --template blog --env dev
hcms seed --file mein-seed.json        # eigenes hcms/seed@1-Template

hcms types generate

Laedt GET /api/v1/collections?include=fields (rohe Felddefinitionen, read-Scope) UND GET /api/v1/blocks?environment= (aufgeloeste Block-Definitionen: Built-ins + DB) und generiert eine TypeScript-Typendatei:

  • pro Collection ein Data-Interface (Literal-Unions aus choices, discriminated unions fuer flexible_content ueber acf_fc_layout, Inline-Interfaces fuer group/repeater), eine Entry-Huelle (<Name>Entry extends HcmsEntryEnvelope<...>) und die Map HcmsCollectionMap (Slug → Data-Typ) fuer createClient<HcmsCollectionMap>();
  • pro Block ein <Slug>Props-Interface (gleiches Feld-Mapping wie Collections; Container-Bloecke bekommen children NICHT als Prop — renderBlocks rendert die Kinder aus dem Block-Baum), plus HcmsBlockRegistry (Slug → ComponentType<Props>) und HcmsBlockSlug (Union). Der einzige Import der generierten Datei ist dann ein reiner import type { ComponentType } from "react".

Geschrieben wird nur bei geaendertem Schema-Hash (deckt Collections UND Bloecke ab); --watch pollt (Default 5s, --interval <sek>).

hcms types generate
hcms types generate --env dev --watch --interval 10

--scaffold-blocks [--dir components/blocks]

Erzeugt zusaetzlich fuer jeden Block-Slug OHNE vorhandene Datei einen typisierten Komponenten-Stub <dir>/<slug>.tsx (Default-dir: components/blocks). Die Props kommen aus dem <Slug>Props-Interface der generierten Typendatei; Container-Bloecke rendern props.children. Bestehende Dateien werden NIE ueberschrieben. Am Ende gibt die CLI ein Registry-Snippet (import-Zeilen + typisierte blocks-Map) zum Kopieren nach components/blocks/registry.tsx auf stdout aus.

hcms types generate --env dev --scaffold-blocks
hcms types generate --scaffold-blocks --dir src/blocks

hcms docs pull

Laedt die per-Organisation generierte LLM-Doku (GET /api/v1/llms-full.txt, Bearer-Token) und schreibt sie als Datei ins Repo (Default cms/llms-full.txt bzw. docsOut). Als lokale Datei kann z.B. Claude Code die Doku direkt lesen.

Schema-as-Code

hcms schema pull

GET /management/schema (manage-Scope) und schreibt in den schemaDir (Default cms/schema):

cms/schema/
  manifest.json            # { "$format": "hcms/manifest@1", environment, pulledAt }
  collections/<slug>.json  # { "$format": "hcms/collection@1", slug, name, settings, fields }
  components/<slug>.json   # { "$format": "hcms/component@1", ... }

Dateien sind kanonisch serialisiert (Objekt-Keys sortiert, 2-Space-Indent, Newline am Ende) → stabile Git-Diffs. schemaVersion wird bewusst NICHT geschrieben (Server-Zaehler). Nicht mehr existierende Dateien werden beim Pull entfernt (Pull ist ein Spiegel des Server-Stands).

hcms schema push / hcms schema diff

Liest die Dateien aus dem schemaDir und PUT /management/schema: idempotenter Upsert per slug, loescht nie (nur im Ziel vorhandene Objekte werden lediglich gemeldet). --dry-run (bzw. schema diff) liefert den Server-Diff, ohne zu schreiben. Environment-Prioritaet: --env > Config > manifest.json (Herkunft des letzten Pull).

hcms schema pull --env dev
hcms schema push --env production --dry-run   # erst pruefen ...
hcms schema push --env production             # ... dann anwenden

Baukasten-as-Code (Bloecke, Layouts, Theme)

Analog zu Schema-as-Code werden auch Bloecke, Layouts und Theme-Tokens als kanonische, Git-diffbare Dateien gepflegt (alle Management-API, manage-Scope, idempotenter Upsert per slug, loescht nie — nur-im-Ziel wird gemeldet). --dry-run (bzw. ... diff) liefert den Server-Diff +neu ~aktualisiert unveraendert, ohne zu schreiben.

hcms blocks pull|push|diff

GET/PUT /management/blocks schreibt/liest eine hcms/block@1-Datei je Slug im blocksDir (Default cms/blocks). Der Pull exportiert nur DB-Definitionen (source != code) — Built-in-Bloecke sind Code und werden nie exportiert. Ein Push mit einem Built-in-Slug lehnt der Server mit 422 VALIDATION_ERROR (Slug-Liste) ab. schemaVersion (Server-Zaehler) landet nie in der Datei.

hcms layouts pull|push|diff

GET/PUT /management/layouts mit hcms/layout@1-Dateien im layoutsDir (Default cms/layouts). Der Server validiert den Block-Baum gegen die aufgeloesten Block-Definitionen des Ziel-Environments — unbekannte Block-Typen → 422. Beim Deployen daher erst blocks push, dann layouts push (sonst schlaegt die Baum-Validierung fehl).

hcms theme pull|push|diff

GET/PUT /management/themes mit hcms/theme@1-Dateien unter <schemaDir>/themes/<slug>.json (Schema + Themes eines Environments liegen so beisammen). HcmsTheme hat keine slug-Spalte — der Server upsertet per name. Der Datei-slug (= kebab(name)) dient nur als stabiler, Git-diffbarer Dateiname und wird beim Push mitgeschickt; der Server matcht ueber name.

# Empfohlene Deploy-Reihenfolge (dev -> prod):
hcms blocks push  --env prod --dry-run && hcms blocks push  --env prod
hcms layouts push --env prod --dry-run && hcms layouts push --env prod
hcms theme push   --env prod --dry-run && hcms theme push   --env prod

Content

hcms content pull

Laedt alle Eintraege einer Collection (Delivery-GET, paginiert, inkl. syncKey/locale) und schreibt eine hcms/content@1-Datei (kanonisch, Default <contentDir>/<slug>.json):

{
  "$format": "hcms/content@1",
  "collection": "blog",
  "entries": [
    { "syncKey": "…", "locale": "de", "status": "published", "slug": "…", "data": { } }
  ]
}

hcms content push

Liest die Datei und upsertet per Bulk-API (POST /collections/X/entries/bulk, action upsert, Matching per syncKey+locale, Chunks a 100). Idempotent wiederholbar; am Ende Zusammenfassung succeeded/failed (Fehler-Items einzeln, Exit-Code 1 bei Fehlern).

hcms content pull --collection blog --env dev
hcms content push --collection blog --env production

Environments & Promote

hcms env list / hcms env clone / hcms env status

hcms env list
hcms env clone --from production --to dev --name "Entwicklung" --content --pages --theme
hcms env status --op <operationId>

clone legt ein NEUES Environment an (Schema immer; --content, --pages [Seiten+Menus], --theme optional). Der Klon laeuft serverseitig idempotent — nach einem Netzwerk-Timeout ist die Wiederholung gefahrlos (bereits kopierte Objekte werden uebersprungen); Status via env status.

hcms promote

Promotet Schema (+ optional Content/Seiten/Menus/Themes) von einem Quell- in ein BESTEHENDES Ziel-Environment (POST /management/environments/promote). --conflict steuert die Strategie bei abweichenden Ziel-Objekten (CLI-Default: overwrite; fail bricht VOR dem ersten Write ab).

hcms promote --from dev --to production --dry-run                 # Diff ansehen
hcms promote --from dev --to production --with-content --pages    # anwenden
hcms promote --from dev --to production --collections blog,page --conflict skip

Dry-Run gibt den Schema-Diff und die Content-Zaehler je Collection aus; die echte Ausfuehrung Stats (neu/ueberschrieben/uebersprungen/unveraendert) und Warnings.

Deprecated: content export / content import

content export schreibt JSON oder CSV (Format aus --format oder der --out-Endung; data-Felder bei CSV flach). content import legt Eintraege per Einzel-POST an (nur create, kein Upsert). Beide geben eine Deprecation-Warnung aus — fuer Roundtrips content pull/content push verwenden.

Tests & Build

npm run test --workspace=@kailua-packages/headless-cli        # vitest (Mock-fetch, keine echte HTTP/DB)
npm run typecheck --workspace=@kailua-packages/headless-cli
npm run build --workspace=@kailua-packages/headless-cli

templates/ (Seed-Templates) ist eingecheckt und via files im npm-Paket enthalten. Fuer ein npm-Publish muss der Build zusaetzlich das Starter-Template (<repo>/templates/frontend-starter) nach templates/frontend-starter kopieren (siehe Kommentar in package.json) — im Monorepo greift hcms init per Dev-Fallback direkt auf <repo>/templates/frontend-starter zu.