@webmate-studio/cli
v0.5.0
Published
Webmate Studio CLI - Build and manage your Webmate components
Readme
@webmate-studio/cli
Command-line tool for Webmate Studio component development and synchronisation.
npm install -g @webmate-studio/cliCommand overview
| Command | Purpose |
|---|---|
| wm init [dir] | Bootstrap a new component project |
| wm generate [type] [name] | Scaffold a new component or island |
| wm dev | Run the local preview server |
| wm install | Install npm deps in the project and per-component package.jsons |
| wm login / wm logout / wm whoami | CLI authentication |
| wm components ls | List the components of the current website |
| wm versions [component] | List published versions of a component |
| wm status [dir] | Sync state — one component, or the whole workspace |
| wm diff [dir] | What changed locally, line by line |
| wm pull [dir] | Download a component version from the CMS |
| wm push [dir] | Upload local changes as a new version |
| wm stash | Park local changes without pushing (shared with the preview UI) |
| wm reset [dir] | Unlink components after copying them into another workspace |
| wm recovery [dir] | List or restore the safety snapshots taken before overwrites |
| wm doctor [dir] | Check the workspace setup for common problems |
| wm build [dir] | Run the cloud build locally to validate before pushing |
wm status, wm push --all and wm pull --all work across a whole workspace;
everything else takes one component.
Cloning moved into the CMS component library (gallery → clone, also across
websites in one organisation). Bring the copy down with wm pull --id <uuid>.
Exit codes
Scriptable, so a pipeline does not have to parse output.
| Code | Meaning |
|---|---|
| 0 | Success — and for wm status, nothing needs a decision |
| 1 | Command failed, or wm status/wm doctor found something to act on |
| 2 | Usage problem: bad flag, or a confirmation is needed with no TTY |
| 3 | wm pull --strategy merge wrote conflict markers that need resolving |
| 130 | Cancelled with Ctrl-C |
Authentication
Most sync commands require a Webmate session. The CLI looks for credentials in this order:
WEBMATE_TOKENenvironment variable (with optionalWEBMATE_BASE_URL)~/.webmate/auth.json(created bywm login).webmate/config.jsonin the current workspace (withapiToken)
wm login itself resolves the target baseUrl in this order:
--base-urlflagWEBMATE_BASE_URLenvironment variablebaseUrlfield in the nearest.webmate/config.json(workspace default)- The built-in default
A workspace-level .webmate/config.json with just { "baseUrl": "https://app.webmate-studio.com" } is enough to pin all subsequent wm login calls in that directory to the right environment.
Interactive login (recommended)
wm loginOpens your browser at the active Webmate instance, shows a verification code, and waits while you click Authorize. The resulting token is saved to ~/.webmate/auth.json with 0600 permissions.
wm login --base-url https://app.webmate-studio.io # switch environment
wm login --force # overwrite an existing sessionNon-interactive (CI/CD)
export WEBMATE_TOKEN="wms_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx"
export WEBMATE_BASE_URL="https://app.webmate-studio.io"
wm push ./my-heroCreate tokens under Settings → API Tokens in the CMS.
The sync workflow
A typical component lifecycle:
# Start from an existing component
wm components ls # find the UUID you want
wm pull ./my-hero --id <uuid> # download it
# … edit files …
wm status # see what changed
wm push # publish a new versionOr from scratch:
wm init my-components
cd my-components
wm generate my-hero # scaffolds component.json with a fresh UUID
wm dev # iterate locally
wm push --force # first push needs --force (no baseVersion yet).webmate.json — local manifest
After wm pull or wm push the CLI writes a .webmate.json next to your component:
{
"componentId": "f97e376c-f8bd-42e4-9b9a-c2d62d4dcc9a",
"baseVersion": "cmn7b9r7p00014i013dk007hw",
"version": "1.0.5",
"pulledAt": "2026-05-20T18:31:46.791Z",
"fileHashes": {
"component.html": "c2689e…",
"component.json": "088e8d…"
}
}The CLI uses baseVersion for optimistic locking on push and fileHashes for change detection. The Workbench desktop app shares the same file format.
Conflict handling
wm push checks the remote head before uploading. If the remote moved since your last pull, the push is refused:
[ERROR] Remote moved: your baseVersion is cmABC… but remote latest is cmDEF… (1.0.6).
Run wm pull first, then push again.Resolve by pulling, merging locally, and pushing again.
wm pull warns about uncommitted local changes and prompts before overwriting, unless --force is given.
Git snapshot
If the component directory is a git repo, wm pull and wm push automatically git add . && git commit a snapshot of the synced state. This is purely a local backup — nothing is pushed to a remote. Disable with --no-git.
Commands
wm login
wm login [--token <wms_...>] [--base-url <url>] [-f|--force]Default flow opens the browser and waits for a verification click — no copy/paste needed. With --token it accepts a pre-generated token directly (useful when scripting or behind firewalls).
wm whoami
wm whoami [--local]Shows the active token source, base URL, user, and organisation. --local skips the /api/auth/me round-trip.
wm components ls
wm components ls [--category <cat>] [--search <q>]Lists the components of the website this workspace targets. Components live per
website, so there is no organisation-wide list. --category and --search are
substring filters over the returned list.
wm versions [component]
wm versions [<uuid> | <dir>] [--limit <n>]Lists all published versions, newest first. The positional argument can be a UUID, a directory containing component.json or .webmate.json, or omitted to use the current directory.
wm status [component]
wm status [<dir>] [--offline]In a component folder, the detailed view. In a workspace root (a folder with a
components/ subfolder), one row per component with a summary — which is how
you answer "is there anything to push?" without visiting every folder.
States:
in sync— local files match the manifest, and the manifest matches what the CMS serveslocal changes— edits that have not been pushednewer in CMS— the CMS moved past yourbaseVersionlocal + CMS changed— both sides moved; may still merge cleanlynot pushed yet— the CMS has never seen this componentlocal only (gone in CMS)— it was deleted therenot linked— no.webmate.jsonyet
--offline skips the network call and only reports the local diff. Exit code is
0 when nothing needs a decision, 1 otherwise.
wm pull [component]
wm pull [<dir>] [--id <uuid>] [--version <ver|cuid|latest>]
[--strategy replace|merge|keep-extra] [--force] [--no-git]Downloads the source bundle of the requested version and rewrites
.webmate.json. Defaults to latest.
| --strategy | Effect |
|---|---|
| replace (default) | The folder ends up matching the CMS version 1:1 |
| merge | 3-way merge; lines both sides changed get <<<<<<< markers, everything else resolves silently |
| keep-extra | Like replace, but files the CMS version does not contain stay |
With local changes and no strategy given, the CLI asks. After a merge that left
markers, wm status keeps reporting local changes and the exit code is 3 —
resolve the markers, then push.
--mergeused to meankeep-extrawhile the preview UI used "merge" for the 3-way merge, so the same word meant opposite things and the CLI one discarded local edits. The flag now errors and names both successors.
wm push [component]
wm push [<dir>] [-m|--message <msg>] [--force] [--no-git]
wm push --all [--dry-run] [-y|--yes] [-m <msg>]Uploads the current file tree as a new patch version. The server bumps SemVer automatically (e.g. 1.0.5 → 1.0.6). The CLI:
- runs a pre-flight
GET /versionsto detect a moved remote and refuses to upload on mismatch - skips uploads when nothing changed since the last pull/push (override with
--force) - treats HTTP 409 as a late-conflict signal and HTTP 422 as a build failure
wm diff [component]
wm diff [<dir>] [--stat] [--path <file>] [--version <ver>]
[--context <n>] [--no-color]Line-by-line changes against the version the workspace last pulled — the same
baseline push locks against, so the diff is what a push would send. --version
compares against any published version instead.
wm stash
wm stash list backups for this component
wm stash save [-m <msg>] [--name <name>] [--force]
wm stash apply [<id>] [--keep] [--force] [-y]
wm stash drop <id> [-y]Named local backups, stored under <workspace>/.webmate/stash/. The preview UI
calls them "Sicherungen" and reads the same store, so a backup made in either
place shows up in both.
apply defaults to the newest and accepts a list number, an id, an id prefix or
a name. It takes a recovery point first and refuses over uncommitted work
without --force; the backup is consumed unless you pass --keep.
Distinct from wm recovery: recovery points are written automatically before
something destructive and live on git refs. Stashes are deliberate, named, and
work without git.
Batch operations
wm status every component, one row each
wm push --all [--dry-run] [-y] everything with local changes
wm pull --all [--dry-run] [-y] [--strategy merge]Run from a workspace root. Both scan first, print what they intend to touch and
ask. Components that need a decision are skipped and named rather than guessed
at — a diverged component is neither pushed (it would overwrite the CMS) nor
pulled (it would overwrite local work) unless --strategy merge says how.
Cloning
wm clone is gone. It was built on the organisation-component API, which the
CMS removed when components moved to living per website.
Clone in the CMS component library instead — gallery → clone, including across websites in the same organisation. The CMS mints a fresh UUID and rebuilds the artefacts. Then bring the copy down:
wm pull --id <new-uuid>Where things live
- Token store:
~/.webmate/auth.json(chmod0600) - Workspace org config:
<your-apps-root>/.webmate/config.json - Per-component manifest:
<component>/.webmate.json
Troubleshooting
Not logged in. → Run wm login, or check WEBMATE_TOKEN is set.
Remote moved: your baseVersion is … → Someone else (or the Workbench, or another machine) pushed a new version. Run wm pull to re-sync, resolve any conflicts, then wm push again.
Build failed (HTTP 422) → The build service rejected the artifact. Check the server logs in the CMS for details; common causes are island files that fail to bundle or invalid component.json.
Token rejected (HTTP 401) → The token has been revoked or expired. Run wm login --force to refresh it.
No .webmate.json found (wm push) → The directory has not been linked to a component yet. Either run wm pull --id <uuid> first, or push with --force to skip the safety check (useful right after wm generate).
