@42ws/cli
v0.0.35
Published
Publish static sites in one command
Maintainers
Readme
@42ws/cli
Publish static sites in one command.
Usage
npx @42ws/cli@latest login --token ws_xxx
npx @42ws/cli@latest publish --site my-site --dir distCommands
42ws login
Authenticate with your 42ws token.
42ws login --token ws_xxx
42ws login --token ws_xxx --api-url https://api.dev.42ws.comIf --token is omitted, you will be prompted to paste your token interactively.
42ws publish
Publish a static site.
42ws publish --site my-site --dir dist
42ws publish --site my-site --build "npm run build"
42ws publish --site my-site --message "Release v1.0"
42ws publish --site my-site --jsonOptions:
--site <name>— Site name (required, or set in42ws.json)--dir <path>— Output directory (default:dist)--build <cmd>— Build command to run before publishing--no-build— Skip the build step--message <text>— Deployment message--yes— Skip non-destructive confirmation prompts--allow-detach— Allow publish even when it would remove an embedded form--json— Output results as JSON
Embed protection: if any AI-imported form is linked to this site (linkedSite), the CLI refuses to publish when the local source no longer contains the embed snippet (looking for data-api-key="<form-key>"). Use --allow-detach to override.
42ws pull
Download the live published files of a site to a local directory. Useful before re-publishing a site that has linked forms — pull, merge your changes, then publish.
42ws pull --site my-site --dir ./live42ws sites
42ws sites list
42ws sites create <name>
42ws sites delete <name> --forcesites delete is destructive and requires --force (not just --yes). If the site has linked forms, the CLI prints them and asks whether to also delete them. Use --delete-forms / --keep-forms for non-interactive control.
42ws forms import
Extract a form from existing HTML and create a 42ws form (Claude Haiku is used to identify fields, theme color, and CSS).
42ws forms import --site my-site --page contact.html --notify [email protected] --inject
42ws forms import --url https://example.com/contact --notify [email protected]
42ws forms import --file ./contact.html --notify [email protected] --injectSource (one required):
--site <name> --page <html>— Pull from a 42ws-hosted site page--url <url>— Fetch from any URL--file <path>— Read from a local HTML file
Options:
--notify <email>— Notification email (required)--name <name>— Override the AI-extracted form name--inject— Replace the source<form>with the embed snippet--sitemode: re-publishes the page--filemode: overwrites the local file
42ws whoami
Show the currently logged-in user.
42ws whoamiLocalization
The CLI auto-detects locale from LANG / LC_ALL env vars and falls back to the OS locale via Intl. Override explicitly with --lang ja or --lang en. Currently supports English and Japanese.
Configuration file
Place a 42ws.json in your project root:
{
"site": "my-site",
"build": "npm run build",
"output": "dist"
}CLI arguments take precedence over the configuration file.
Environment variables
| Variable | Description |
|---|---|
| FORTYTWO_WS_TOKEN | Override the stored auth token |
| FORTYTWO_WS_API_URL | Override the API URL |
JSON output mode
Use --json for machine-readable output (useful in CI / AI agents):
Success:
{"ok":true,"status":"published","url":"https://my-site.dev.42ws.com","site":"my-site","version":"pub_xxx"}Failure:
{"ok":false,"error":{"code":"NOT_LOGGED_IN","message":"You are not logged in.","suggestedFix":"Run `42ws login --token <your-token>` to authenticate."}}Every error includes a code, message, and suggestedFix. AI agents should read suggestedFix and apply the suggested change before retrying.
For AI Agents
This CLI is designed to be driven by AI coding agents (Claude Code, Cursor, etc.).
Recommended invocation
npx @42ws/cli@latest publish --yes --json--yesskips all interactive prompts--jsonmakes output machine-readable
Behavior contract
- All commands return
{"ok": true, ...}on success or{"ok": false, "error": {...}}on failure. - Errors always include
code,message, andsuggestedFix. ReadsuggestedFixand apply it before retrying. - The CLI never opens a browser or asks for input when
--yesis set. - Site names are auto-derived from the directory name when
--yesis set and no--siteis given. - Frameworks (Vite / Astro / Next static export / SvelteKit static / plain HTML) are auto-detected from
package.jsonand the directory contents.
Rules for AI agents
- Do not ask the user for AWS credentials, S3 buckets, or CloudFront — 42ws abstracts these away.
- Do not publish backend code (API routes, server functions, databases). Only static files.
- Do not publish secret files. The CLI rejects
.env,.git/,node_modules/,*.pem,*.key,id_rsa,id_ed25519automatically. - Do read
error.suggestedFixand apply it before retrying. - Do return the published URL to the user.
Common error codes
| Code | Meaning | Fix |
|---|---|---|
| NOT_LOGGED_IN | No saved auth | Run npx @42ws/cli@latest login (browser auth) |
| INVALID_SITE_NAME | Site name missing or invalid | Add --site <name> or pass --yes to use directory name |
| RESERVED_SITE_NAME | Subdomain reserved | Pick a different name |
| SITE_NAME_TAKEN | Site already owned by someone | Pick a different name |
| OUTPUT_DIR_NOT_FOUND | dist/ etc. missing | Run the build command first or pass --dir <path> |
| NO_FILES_FOUND | No files to publish | Check --dir is correct |
| BLOCKED_FILE | Secret file would be uploaded | Remove the file or add to .gitignore |
| BUILD_FAILED | Build command exited non-zero | Fix the build error first |
| FORBIDDEN | License not enabled or not site owner | Ask the account owner |
| EMBED_DETACH_BLOCKED | Publish would remove an embedded form | Pull the live first (42ws pull) and merge, or pass --allow-detach |
| CONFIRMATION_REQUIRED | Destructive op needs explicit confirmation | Add --force |
Suggested user-facing prompt
Users can paste this into their AI assistant:
このプロジェクトを 42ws に公開してください。
npx @42ws/cli@latest publishを使ってください。エラーが出たらerror.suggestedFixの指示に従ってください。
(English: "Publish this project to 42ws using npx @42ws/cli@latest publish. If an error occurs, follow error.suggestedFix.")
