@arcevo/facet-cli
v2.0.0
Published
facet CLI: scaffold docs + email template sites, add components, generate tree-shaken icon registries, and audit/update your facet setup from the terminal.
Maintainers
Readme
@arcevo/facet-cli
Scaffold and generate @arcevo/facet-docs sites. Framework and
language-agnostic: the init wizard asks for your stack and tailors what it
generates, so TypeScript, JavaScript, React+Vite, Next.js, Remix, plain JS,
and even Python repos all get a docs scaffold that fits.
Install
pnpm add -g @arcevo/facet-cli
# or
npx @arcevo/facet-cli
# keep it current globally with the scoped-dropped short name:
facet install -g facet-cli # -> npm i -g @arcevo/facet-cli@latestHow it stays current
The scaffold never pins hardcoded versions. At docs init time the CLI:
- Detects your frontend stack (Next.js, Remix, Vite, plain JS, Python). Backend frameworks (Fastify, Express, Nest, ...) are ignored: docs are a frontend concern, so a fullstack repo like arc-id (Next.js + Fastify) scaffolds for the frontend.
- Detects your package manager from the lockfile (
pnpm/yarn/bun/npm) and recommends the matching install command. - Resolves the current published versions of the facet packages from
the npm registry, so your
package.jsonalways gets the latest compatible release, never a stale pinned guess. - Patches your existing
package.jsonif one is present: your own scripts, deps, name, and metadata are preserved. The docs scripts are added under distinct names (docs:dev,docs:build, ...) so nothing you already have is overwritten. If nopackage.jsonexists, a fresh minimal one is created and your package manager generates the lockfile on first install.
Commands
Run facet --help (or facet -h) to list the available commands and flags
from the terminal. For deeper guides, examples, and the full reference, visit
the CLI documentation at https://docs.facet.arcevocirqle.com.ng/cli.
facet pkg
Show every published @arcevo/facet-* package: the latest registry version,
what your repo declares, and what is actually installed. Flags (update
available) when a newer version exists. Works in single packages and
monorepos (workspace members are scanned for facet deps).
facet doctor
Audit the current repo: package manager, monorepo/workspace layout, which
facet packages are used, and best-practice suggestions (e.g. wire
@arcevo/facet-tokens when components are used without it, swap
workspace:* ranges for registry ranges before publishing, run
facet update when packages are outdated).
facet update
Apply updates for the facet packages that have newer published versions:
installs the outdated @arcevo/facet-* packages at their latest published
versions using the detected package manager, with a confirmation prompt
(skip it with -y). Pass --dry-run to only print the exact install
command. In a monorepo it detects the workspace layout and includes the
root/workspace flag.
facet up
Apply the facet package updates (the always-apply variant of facet
update): installs the outdated @arcevo/facet-* packages at their latest
published versions using the detected package manager without prompting.
Pass --dry-run to only print the command.
facet clean
Consumer-safety cleanup for repos that use @arcevo/facet-components. It
finds dependencies the package already bundles (radix primitives,
lucide-react, cmdk, input-otp, qrcode.react, react-hook-form,
sonner, class-variance-authority, clsx, tailwind-merge), removes them
from your manifests, rewrites shadcn/ui-style imports (and direct
radix/lucide imports) to @arcevo/facet-components, and deletes dead local
ui/ components.
Safe by default:
--dry-runshows the full plan without touching anything.- Without
--dry-runit prompts for confirmation (or-y). - It prints the exact remove command (
pnpm remove .../npm uninstall ...) instead of auto-running it, so you control the lockfile change.
facet emails init
Scaffold or migrate email templates wired to @arcevo/facet-emails. It
detects the consumer's mail setup from the manifests:
- react-email / mjml / nodemailer present -> offers to migrate (build the
facet-emails
emails/dir + preview server on top of what exists). - resend / sendgrid / SES / postmark present -> wires the provider into
the generated
send.ts. - nothing -> fresh scaffold:
emails/brand.ts(theme tokens),emails/layout.tsx,emails/template-registry.tsx,emails/preview-server.ts,emails/send.ts(resend/nodemailer/no provider), and.env.example.
It auto-installs @arcevo/facet-emails (and the provider SDK) via the
detected package manager, fails soft printing the exact command when the
install can't run, and prints the setup guide (provider keys, preview URL,
how to send).
Flags: -y (no prompts), --framework, --migrate / --fresh,
--provider resend|nodemailer|none, --location (default emails),
--name (brand name).
facet templates
Work with consumer template directories: your own starter files that
docs init and emails init can merge into the generated scaffold.
Templates live under ./templates/<name>/ (or ./docs/templates/,
./emails/templates/), optionally with a template.json manifest:
{
"name": "saas-product",
"kind": "docs",
"description": "SaaS product docs",
"include": ["**/*"],
"exclude": ["**/node_modules/**"]
}facet templates list: discover template dirs in the repo.facet templates describe <name>: show a template's manifest + files.
facet docs init --use-template <name>
After scaffolding the docs site, merge the named template directory over it. The merge is never destructive by default:
- New paths → copied in.
- Existing identical files → skipped.
package.json→ merged (your fields always win).- Code files containing a
// @facet-mergemarker → the marker's contents are appended before the file's final}(an opt-in way to merge the implementation in). - Any other existing file → skipped (reported as a conflict; use
--forceto overwrite).
This lets you keep your own starter pages, layouts, or components in
./templates and have the scaffold build on top of them instead of
replacing them.
facet emails init --use-template <name>
Same merge, applied to the email scaffold: after emails init generates
the emails/ dir, the named template's files are merged in.
facet scripts
Add useful npm scripts to your package.json, preserving anything you
already have:
- Docs:
docs:dev,docs:build,docs:preview - Quality:
lint,typecheck,test,build - facet convenience:
facet:doctor,facet:clean,facet:prep - Pre-go-live:
facet:prep
Prompts for which presets to add (or -y to add all). Existing scripts are
never overwritten.
facet prep
Pre-go-live sync. Runs read-only checks plus your own gates:
facet pkg- are your facet deps current?facet doctor- is your setup healthy (tokens wired, no unnecessary bundled deps)?- Your own
typecheck/build/testscripts, when they exist. pnpm changeset status- in a monorepo, the pending release set.
Prints a PASS/FAIL summary per step; exits non-zero when something needs fixing before go-live.
facet docs init
Interactive wizard that scaffolds a docs site in the current repo. It opens
with a "Decide for me" option: detect my stack and use the best
defaults (also available non-interactively via --yes / -y), or walks
you through each choice:
- Name: leave blank to use the default
docs - Location (
.recommended, ordocs/,src/docs/) - Language (TypeScript / JavaScript)
- Framework (React+Vite, Next.js, Remix, plain JS, Python)
- Styling (detected from your repo; facet tokens recommended)
- Template kind (component library / API reference / product docs)
- Barrel export:
auto(recommended): create anindex.tswhen it fits the layout;always: force one;never: leave your tree untouched
Every prompt describes what the choice represents, so you know what each step will generate before committing.
After scaffolding, the CLI installs the facet packages automatically at their current published versions (the CLI resolves them from the npm registry, so you always get the latest safe release - no pinned guesses). If the install can't run (offline, no package manager), it prints the exact command instead.
For React+Vite it generates a complete thin-consumer app (like facet's
own apps/docs): package.json, Vite config, src/main, src/app, and a
src/pages registry. For Next.js it scaffolds a real src/app/docs
route ("use client" rendering DocsApp) plus src/lib/docs/config and
src/lib/docs/pages, so the docs mount at /docs in your existing Next
app: with next/react deps and docs:dev/docs:build scripts added.
For Remix it scaffolds a real app/routes/docs route rendering
DocsApp plus the same src/lib/docs config + pages, with
@remix-run/react deps and docs:dev/docs:build scripts. For plain
JS it generates a framework-agnostic pages registry + a markdown
content pipeline with no React shell. For Python it generates a
docs_pipeline.py markdown → pages.json compiler plus a starter
registry, so a Python repo owns its docs in markdown and hands the JSON
to any React host for rendering.
The scaffold never copies facet's own docs. You get the engine
(@arcevo/facet-docs) and an empty pages registry to fill with your
content.
facet add <component>
Copy a component into your source (shadcn-style). Recommended: import
from @arcevo/facet-components instead: you get updates, tree-shaking,
and the token system. Copying source means you own every future fix. This
exists for consumers who prefer a copy-into-source workflow.
Placement is flexible and stays out of your way:
- By default (
decide), the CLI detects what you already have and wires up the best layout: components go flat into your components root when it already has a barrel (so they're importable immediately), otherwise into a cleanfacet/subdirectory. --dir <dir>chooses the components directory (defaultsrc/components).--ui-dir <name>names the subdirectory that holds the copies (defaultfacet, shadcn'sui/pattern). Ignored with--flat.--flatplaces components directly in the root instead of a subdirectory.--no-barrelskips creating or updating any barrel export.--barrelalways creates a barrel (even when none exists yet).
When a barrel already exists, the CLI merges a single re-export into it:
your own exports are never overwritten. The generated subdirectory barrel
(facet/index.ts) is kept in sync as you add more components, so you can
import like:
import { Button, Badge } from "@/components/facet";Theming
When you choose facet tokens, the scaffold wires @arcevo/facet-tokens
(tokens.css + tailwind.css) and the ThemeProvider + overrideVars story,
so you get the whole Alpha Palette system (dark mode, frost/glass surfaces)
with one import instead of restyling every component.
Development
pnpm build # tsup -> dist
pnpm typecheckWhy a CLI?
The @arcevo/facet-docs package is an engine: it ships the shell, gallery,
and block types, but no authored content. facet docs init gives consumers
a starting point without forking or cloning: the engine stays installable,
the content stays theirs.
