docs: expand README and documentation site with concepts, getting-started, and CLI reference pages

- Add `concepts.mdx` covering categories, cardinality, home, vendoring, peers/adapters, manifest, regions, and the open registry model
- Flesh out `getting-started.mdx` with prerequisites, install/run steps, package-manager variants, inspect/remove commands, and a non-interactive `--yes` example
- Rewrite `cli-reference.mdx` with per-verb sections, global flags, environment variables, and dependency-versioning semantics
- Expand `README.md` with a "Why Stanza?" section, quick-start snippet, docs link, and updated module list; swap `pnpm create` example for `npm init`
- Add `concepts` to `meta.json` nav order
This commit is contained in:
2026-05-22 16:03:15 -04:00
parent 54de4cf892
commit 9bf80ce2e8
20 changed files with 345 additions and 59 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
---
"@stanza/cli": minor
"stanza-cli": minor
---
Add multi-choice **add-on** modules. A `Module` is now a discriminated union on `kind` (`"slot"` default, or `"addon"` carrying a `category`), and `stanza.json` records add-ons in a new `addons` field keyed by category (each holding 0..n modules). Add-on categories (`testing`, `tooling`, `deploy`, `email`, `monorepo`) are disjoint from slots, so they never constrain another module's adapter dispatch — but they can still target a framework via `peers` + per-framework adapters.
+1 -1
View File
@@ -1,5 +1,5 @@
---
"@stanza/cli": minor
"stanza-cli": minor
---
Unify the module taxonomy into one `Category` concept. The old slot/add-on split
+1 -1
View File
@@ -1,5 +1,5 @@
---
"@stanza/cli": minor
"stanza-cli": minor
---
Add a single-choice **tooling** slot for the lint/format toolchain, with three modules: `eslint-prettier` (ESLint flat config + Prettier, per-framework adapters), `biome`, and `oxlint-oxfmt` (both framework-agnostic). Modeled as a slot rather than a multi-choice add-on because the three toolchains are mutually exclusive substitutes.
+1 -1
View File
@@ -55,7 +55,7 @@ jobs:
run: pnpm test
- name: Build CLI bundle
run: pnpm --filter @stanza/cli build
run: pnpm --filter stanza-cli build
- name: Smoke-test built CLI
run: |
+4 -4
View File
@@ -10,7 +10,7 @@ Three things differentiate stanza from other scaffolders:
## Layout
- `apps/cli/``@stanza/cli`, node entrypoint at `src/bin.ts` (run via tsx in dev, tsdown-built to `dist/bin.mjs` for publish)
- `apps/cli/``stanza-cli`, node entrypoint at `src/bin.ts` (run via tsx in dev, tsdown-built to `dist/bin.mjs` for publish)
- `apps/web/``@stanza/web`, TanStack Start visual builder (Vite-native, no Vinxi)
- `packages/registry/` — shared schema, category/peer resolver, Zod manifest validator
- `packages/codemods/` — ts-morph helpers (idempotent + reversible)
@@ -22,8 +22,8 @@ In a **generated project**, a module's output lands per its category's `home` (i
## Commands
- `pnpm --filter @stanza/cli dev -- <verb>` — run CLI directly via `tsx watch ./src/bin.ts`; no build step. Or `tsx apps/cli/src/bin.ts <verb>` for a one-shot run
- `pnpm --filter @stanza/cli build` — build the publishable CLI via tsdown (compiles to ESM JS at `apps/cli/dist/`, externalizes npm deps, inlines workspace packages). Same for `create-stanza`
- `pnpm --filter stanza-cli dev -- <verb>` — run CLI directly via `tsx watch ./src/bin.ts`; no build step. Or `tsx apps/cli/src/bin.ts <verb>` for a one-shot run
- `pnpm --filter stanza-cli build` — build the publishable CLI via tsdown (compiles to ESM JS at `apps/cli/dist/`, externalizes npm deps, inlines workspace packages). Same for `create-stanza`
- `pnpm registry:build` — regenerate `dist/registry/{index,modules/*}.json`. Uses bun for maintainer convenience (the script body is portable; `tsx scripts/registry-build.ts` works too)
- `pnpm --filter @stanza/web dev` — TanStack Start dev server. `prebuild` invokes [`apps/web/scripts/prepare-registry.sh`](apps/web/scripts/prepare-registry.sh) which copies the built `dist/registry/` into `apps/web/public/registry/`. Since `dist/registry/` is gitignored, the script builds it first when it's missing (e.g. on Vercel's clean checkout) — preferring `bun` locally and falling back to `pnpm exec tsx` on node-only deploy targets. The deployed site ships this directory as static assets, so CLI and web consume the same JSON. `public/registry/` is also registered as a Nitro `serverAssets` dir (vite.config.ts), so its contents are embedded into the server bundle at build time — SSR reads it via `useStorage("assets:registry")` (not the CDN), which is why it works on Vercel where `public/` is absent from the function fs
- `pnpm lint` / `pnpm lint:fix` — Oxlint across the whole repo (config: `.oxlintrc.json`)
@@ -54,7 +54,7 @@ Core workflow:
- **Node-only at runtime.** The CLI source uses node APIs and is dev-run via `tsx`; the published binary is plain ESM JS (`#!/usr/bin/env node`). The only place bun appears is the shebang on root maintainer scripts (`scripts/*.ts`) for our own convenience — those scripts don't use any `Bun.*` APIs and run fine under tsx/node
- **Build pipeline**: `tsdown` compiles each publishable package to ESM JS in `dist/`. External npm deps are _not_ bundled (users install them via the normal dep chain); workspace deps are _inlined_ (we don't publish `@stanza/registry` and `@stanza/codemods` separately). Transitive runtime deps (`ts-morph`, `zod`) MUST be declared as direct `dependencies` of the publishable package or tsdown will inline them into the bundle
- **Per-workspace `dist/` paths**: `main`/`types` in the source `package.json` still point at `./src/` so other workspaces resolve `.ts` directly during dev. The published tarball overrides via `publishConfig` to point at `./dist/<x>.mjs`/`.d.mts`
- **Publishing**: only `@stanza/cli` and `create-stanza` ship to npm. `@stanza/codemods` + `@stanza/registry` are marked `private: true` (inlined into the CLI bundle by tsdown); `@stanza/web` is private (deployed as a Vercel site, not an npm package); the `registry/modules/*` packages are also private (they're registry data, not npm packages). Releases go through **Changesets**: drop a markdown file via `pnpm changeset`, push to main → the [release workflow](.github/workflows/release.yml) opens a "Version Packages" PR; merging that PR triggers the same workflow to run `pnpm release` (build CLI + create-stanza, then `changeset publish` to npm). Requires `NPM_TOKEN` in repo secrets; provenance attestations are emitted via `id-token: write` + `NPM_CONFIG_PROVENANCE=true`
- **Publishing**: only `stanza-cli` and `create-stanza` ship to npm. `@stanza/codemods` + `@stanza/registry` are marked `private: true` (inlined into the CLI bundle by tsdown); `@stanza/web` is private (deployed as a Vercel site, not an npm package); the `registry/modules/*` packages are also private (they're registry data, not npm packages). Releases go through **Changesets**: drop a markdown file via `pnpm changeset`, push to main → the [release workflow](.github/workflows/release.yml) opens a "Version Packages" PR; merging that PR triggers the same workflow to run `pnpm release` (build CLI + create-stanza, then `changeset publish` to npm). Requires `NPM_TOKEN` in repo secrets; provenance attestations are emitted via `id-token: write` + `NPM_CONFIG_PROVENANCE=true`
- pnpm 10 + `node-linker: isolated` — each workspace MUST declare `@types/node` in its own devDeps and set `types: ["node"]` in tsconfig (auto-discovery doesn't reach into the isolated `node_modules/@types`)
- TypeScript 6 — `allowImportingTsExtensions: true` + `noEmit: true` is set in `tsconfig.json`; the CLI/create-stanza emit JS via tsdown, the registry/codemods packages stay source-only and never emit
- `tsconfig.json` excludes `**/templates/**` globally — template files target user projects, not this repo
+33 -8
View File
@@ -1,32 +1,57 @@
# Stanza
Modular monorepo template CLI — shadcn for full-stack TypeScript stacks.
Modular monorepo template CLI — aka shadcn for full-stack TypeScript projects.
```sh
pnpm create stanza my-app
npm init stanza my-app
```
Pick a framework, ORM, database, auth provider, styling — get a clean monorepo with idiomatic code, vendored into your repo. Add modules later with `stanza add`.
Pick a framework, ORM, database, auth provider, and styling — get a clean monorepo with idiomatic code, vendored into your repo. Layer in more modules later with `stanza-cli add`.
Generated projects keep slot boundaries explicit: `auth`, `db`, and `orm` install into their own internal workspace packages (`packages/auth/`, `packages/db/`, named `@<your-app>/auth`, `@<your-app>/db`), and your app consumes them via `workspace:*` deps. Swapping an auth provider replaces the contents of `packages/auth/` without touching your app's imports.
## Why Stanza?
- **`add` works after `init`.** Run `stanza add` on an existing project — it's manifest-driven and peer-aware, so it picks the right adapter for your stack and wires deps, env, and templates into the correct workspace package.
- **Your code, vendored.** Generated files land in your repo verbatim. There's no Stanza runtime to install or carry around.
- **Open registry.** Modules are static JSON. Point the CLI at your own host and serve custom modules.
## Quick start
```sh
npm init stanza my-app
cd my-app
npm install
npm run dev
```
Add a module to an existing project at any time:
```sh
npx stanza-cli add auth better-auth
```
`auth`, `db`, and `orm` install into their own internal workspace packages (`packages/auth/`, `packages/db/`, named `@<your-app>/auth`, `@<your-app>/db`); your app consumes them via `workspace:*`. Swapping an auth provider replaces the contents of `packages/auth/` without touching your app's imports.
## Docs
Full guides and the CLI reference live at **[stanza.tools/docs](https://stanza.tools/docs)**. Assemble a stack visually with the builder at **[stanza.tools](https://stanza.tools)**.
## What's inside
```
apps/
cli/ # @stanza/cli — the CLI binary
cli/ # stanza-cli — the CLI binary
web/ # https://stanza.tools (TanStack Start)
packages/
registry/ # shared schema, slot/peer/capability resolver
codemods/ # ts-morph helpers for region-aware patching
create-stanza/ # `pnpm create stanza` shim
registry/
modules/ # first-party modules (framework, orm, db, auth, styling)
modules/ # first-party modules (framework, orm, db, auth, styling, tooling, testing)
```
## Status
## Contributing
Work in progress. See [CLAUDE.md](./CLAUDE.md), [TODO.md](./TODO.md), and [REGISTRY.md](./REGISTRY.md) for current state.
Work in progress. See [CLAUDE.md](./CLAUDE.md) for architecture and toolchain invariants, [REGISTRY.md](./REGISTRY.md) for the module roadmap, and [TODO.md](./TODO.md) for active work.
## License
+2 -2
View File
@@ -126,13 +126,13 @@ The full first-party module roadmap lives in [REGISTRY.md](REGISTRY.md). These a
- [ ] Golden snapshot tests per module combination (per the plan's verification section) — for each valid `(framework, orm, db, auth, styling, pm)` tuple, run `stanza init` headless, snapshot the tree, compare against fixture
- [ ] Integration test for the canonical stack — Docker Postgres + Playwright sign-up flow
- [ ] Registry deploy pipeline — on push to main, build `dist/registry/` and push to Vercel/CF
- [x] npm publish workflow — Changesets configured (`.changeset/config.json`, public access, `@changesets/changelog-github` for PR links). [Release workflow](.github/workflows/release.yml) runs `changesets/action@v1` on push to main: opens a "Version Packages" PR when changesets queue up; merging publishes via `pnpm release` (build CLI + create-stanza, then `changeset publish`). Provenance attestations enabled. Tarball dry-run verified: `@stanza/cli` is 20 KB, `create-stanza` is 1.7 KB; both `npm install`-able from a clean tmpdir and `--version` / `--help` work. Repo needs `NPM_TOKEN` secret before the first publish
- [x] npm publish workflow — Changesets configured (`.changeset/config.json`, public access, `@changesets/changelog-github` for PR links). [Release workflow](.github/workflows/release.yml) runs `changesets/action@v1` on push to main: opens a "Version Packages" PR when changesets queue up; merging publishes via `pnpm release` (build CLI + create-stanza, then `changeset publish`). Provenance attestations enabled. Tarball dry-run verified: `stanza-cli` is 20 KB, `create-stanza` is 1.7 KB; both `npm install`-able from a clean tmpdir and `--version` / `--help` work. Repo needs `NPM_TOKEN` secret before the first publish
- [ ] `.env.example` at repo root listing `STANZA_REGISTRY`, PostHog key, etc.
## Open items from the plan
- [x] Domain — `stanza.tools` (registry served at `https://stanza.tools/registry`, web builder at `https://stanza.tools`)
- [ ] npm scope clearance — `@stanza` scope availability (the CLI assumes `@stanza/cli`); fall back to unscoped `stanza` if taken
- [x] npm name clearance — locked down unscoped `stanza-cli` and `create-stanza` on npm; the CLI publishes as `stanza-cli` (binary stays `stanza`)
- [ ] Better Auth vs Clerk feature parity — Clerk wraps its own UI, Better Auth is headless; document the difference or ship shared UI stubs (`SignInForm`, callback page) that each adapter fills in
## Out of scope for now
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@stanza/cli",
"name": "stanza-cli",
"version": "0.1.0",
"description": "Modular monorepo template CLI — shadcn for stacks.",
"keywords": [
+96 -14
View File
@@ -1,21 +1,103 @@
---
title: CLI reference
description: The stanza command-line verbs at a glance.
description: The stanza command-line verbs, flags, and environment variables.
---
stanza currently ships five verbs against the slot taxonomy. More (`swap`,
`update`) are planned.
stanza ships five verbs against the category taxonomy. Run any verb with
`--help` for its full flag list:
| Verb | What it does |
| -------- | --------------------------------------------- |
| `init` | Scaffold a new monorepo from a stack |
| `add` | Add a module to an existing project |
| `remove` | Remove a module and sweep its claimed regions |
| `list` | List installed modules |
| `search` | Search the registry |
Run any verb with `--help` for its flags:
```bash
```sh
stanza add --help
```
## `init`
Scaffold a new monorepo. Without flags it launches an interactive wizard;
with `--yes` it takes every pick from flags.
```sh
stanza init [name] --yes --framework=next --orm=drizzle --db=postgres --pm=pnpm
```
- `name` — project directory name (positional; prompted if omitted).
- `--yes` — non-interactive; take selections from category flags.
- `--<category>=<ids>` — pick modules for a category. One flag per category
(`--framework`, `--styling`, `--db`, `--orm`, `--auth`, `--tooling`,
`--testing`); single-choice categories take one id, multi-choice categories
take a comma-separated list. Omitted categories are skipped — `--yes` chooses
no defaults.
- `--pm=<pnpm|bun|npm>` — package manager recorded in the manifest.
## `add`
Add one module to an existing project.
```sh
stanza add <category> <module>
```
Resolves peers, selects the matching adapter, and writes the module's templates,
deps, env, and scripts to the right home. Adding a module to a single-choice
category that's already filled fails until you remove the existing one.
## `remove`
Remove a module and sweep the files (regions) it owns.
```sh
stanza remove <category> [id]
```
For single-choice categories the `id` is optional; for multi-choice categories
(like `testing`) it's required.
## `list`
Print installed modules, grouped by category, from the nearest `stanza.json`.
```sh
stanza list
```
## `search`
List registry modules and their `category/id` pairs. Pass a query to filter.
```sh
stanza search [query]
```
Use the printed **id** (not the display label) when passing a module to `add`.
<Callout type="info">
**Planned:** `swap` (replace a module with another in the same category) and
`update` (re-pull a module at a newer version) are on the roadmap. The manifest
already reserves the fields they need; the verbs aren't implemented yet.
</Callout>
## Global flags
These apply to the mutating verbs (`init`, `add`, `remove`):
- `--dry-run` — print the actions that would be taken and write nothing.
- `--dangerously-allow-dirty` — allow a mutating command to run with a dirty git
working tree. By default stanza refuses, so its edits never mix with
uncommitted changes. Commit or stash first when you can.
- `--no-telemetry` — disable anonymous usage events for this invocation.
## Environment variables
- `STANZA_REGISTRY=<url-or-path>` — use a custom or self-hosted registry (HTTP
URL or filesystem path) instead of the default.
- `STANZA_NO_NPM_LOOKUP=1` — skip npm version lookups and write dependency ranges
verbatim.
- `STANZA_NPM_REGISTRY=<url>` — override the npm registry used for version lookups.
- `STANZA_TELEMETRY=0` / `DO_NOT_TRACK=1` — disable telemetry persistently.
Telemetry is also auto-skipped in CI.
## Dependency versioning
On `init` and `add`, stanza bumps each `^`/`~` dependency range to the latest npm
version that satisfies it, keeping the modifier. Other ranges and `workspace:*`
specifiers are written as-is. When offline, it falls back to the range declared
in the module.
+83
View File
@@ -0,0 +1,83 @@
---
title: Concepts
description: The mental model behind stanza — categories, vendoring, peers, and the manifest.
---
A handful of ideas explain how stanza decides what to write and where. Once they
click, the CLI's behavior is predictable.
## Categories
Every module belongs to exactly one **category**. A category has two independent
properties that govern how its modules behave:
- **Cardinality** — `one` (single-choice) or `many` (coexisting).
- **Home** — where a module's output lands: `app`, `repo`, or `package`.
| Category | Cardinality | Home |
| ----------- | ----------- | --------- |
| `framework` | one | app |
| `styling` | one | app |
| `db` | one | package |
| `orm` | one | package |
| `auth` | one | package |
| `tooling` | one | repo |
| `testing` | many | app |
A `one` category holds at most one module — adding a second fails until you
remove the first. A `many` category lets modules coexist (e.g. Vitest and
Playwright side by side).
**Home** decides placement. `app` modules wire your app shell (in `apps/web/`,
say). `repo` modules write config at the monorepo root. `package` modules install
into their own internal workspace package under `packages/<dir>/`, named
`@<your-app>/<dir>`, which your app consumes via `workspace:*`. `db` and `orm`
share a single `packages/db/` so the ORM client sits next to the schema it
queries.
<Callout type="info">
**Planned:** more categories are on the roadmap — `api`, `ai`, `payments`
(single-choice) and `email`, `deploy` (coexisting). They aren't shipping yet,
but the taxonomy is designed to absorb them without breaking existing
projects.
</Callout>
## Vendoring
stanza copies a module's code into your repo verbatim. There's no shared runtime
package — the generated files are ordinary source you can read, edit, and commit.
That means upgrades never silently change your app's behavior, and you're never
locked into stanza's abstractions.
## Peers and adapters
Modules declare **peers** — the other categories they care about. When you `add`
a module, stanza reads your current selections and picks the **adapter** that
matches. Better Auth, for instance, peers on both `framework` and `orm`, so
adding it to a Next + Drizzle app produces different wiring than a TanStack Start
+ Prisma app. You pick the module; stanza picks the right variant.
## The manifest (`stanza.json`)
The `stanza.json` file at your repo root is the source of truth for what's
installed. It records your module selections per category and the **regions** —
the files and file-fragments — each module owns. `add`, `remove`, and `list` all
read it. Treat it as generated state: don't hand-edit it unless you're repairing
something deliberately.
## Regions
A **region** is a claim on a file (or a section of one) by a specific module.
This is how `stanza remove` knows exactly what to delete and what to leave alone:
it sweeps only the regions the removed module owns. Because regions key on the
module, two modules can safely write disjoint parts of the same file — Vitest
owning the `test` script and Playwright owning `test:e2e`, for example, without
conflict.
## Open registry
A registry is just static JSON: an index plus one file per module, each carrying
its templates, dependencies, env vars, and codemod invocations. The CLI ships
with a default registry, but you can point it anywhere — a URL or a local path —
with `STANZA_REGISTRY`. That's the hook for self-hosting your own modules or
pinning a fixture in CI.
+79 -5
View File
@@ -5,20 +5,94 @@ description: Create your first stanza project and add modules.
Scaffold a new monorepo, then layer in modules as you go.
## Prerequisites
- **Node.js** 20 or newer.
- A package manager — **pnpm** (recommended), **npm**, or **bun**. stanza writes
a workspace-based monorepo, so a workspace-aware package manager is required.
## Create a project
```bash
The create command launches an interactive wizard that walks you through each
category:
```sh
pnpm create stanza my-app
```
The same command works across package managers:
```sh
npm create stanza@latest -- my-app
bun create stanza@latest my-app
```
To run it without the wizard — in CI, for example — see
[Non-interactive setup](#non-interactive-setup) below.
## What you get
stanza generates a clean monorepo: your app under `apps/`, internal packages
under `packages/`, and a `stanza.json` manifest at the root. The manifest records
which modules you selected and which files each one owns — it's how `add` and
`remove` know what's installed and what to clean up. You generally don't edit it
by hand.
## Install and run
```sh
cd my-app
pnpm install
pnpm dev
```
## Add a module
Every slot — `framework`, `styling`, `db`, `orm`, `auth` — is one command away:
Every category — `framework`, `styling`, `db`, `orm`, `auth`, `tooling`,
`testing` — is one command away:
```bash
```sh
stanza add auth better-auth
```
stanza resolves peer constraints, picks the right adapter for your stack, and
stanza resolves peer constraints, picks the adapter that matches your stack, and
writes the module's templates, dependencies, and environment variables into the
appropriate workspace package.
appropriate place. For `auth`, `db`, and `orm` that's an internal workspace
package (e.g. `packages/auth/`, named `@my-app/auth`) that your app consumes via
`workspace:*`. After adding a package-scoped module, re-run your package
manager's install so the new workspace package links:
```sh
pnpm install
```
## Inspect and remove
```sh
stanza list # show installed modules, grouped by category
stanza search drizzle # find modules in the registry by query
stanza remove auth # remove a module and sweep the files it owns
```
`stanza search` prints each module's `category/id` pair — use the **id**, not the
display label, when passing it to `add`.
## Non-interactive setup
Pass `--yes` and select each category explicitly with a flag. Single-choice
categories take one id; multi-choice categories (like `testing`) take a
comma-separated list:
```sh
npx -y stanza-cli@latest init my-app --yes \
--framework=next \
--styling=tailwind \
--db=postgres \
--orm=drizzle \
--auth=better-auth \
--testing=vitest,playwright \
--pm=pnpm
```
`--yes` never fills in defaults for categories you omit — any category without a
flag is simply skipped.
+28 -6
View File
@@ -5,13 +5,35 @@ description: Assemble modular full-stack TypeScript monorepos with stanza.
stanza is a shadcn-style CLI for assembling modular full-stack TypeScript
monorepos. Pick a framework, styling, database, ORM, and auth — stanza vendors
the code directly into your repo, with no runtime dependency to carry around.
idiomatic code directly into your repo, with no runtime dependency to carry
around.
## Why stanza
- **Post-init `add`** works on existing projects — manifest-driven and peer-aware.
- **Vendored code** — generated files land in your repo verbatim.
- **Open registry** — host your own static JSON and serve custom modules.
- **`add` works after `init`.** Run `stanza add` on an existing project. It reads
your `stanza.json` manifest, resolves peer constraints, and picks the right
adapter for your stack — so adding auth to a Next + Drizzle app writes
different code than adding it to a TanStack Start + Prisma app.
- **Your code, vendored.** Generated files land in your repo verbatim. There's no
`@stanza/runtime` package to install, and nothing to upgrade out from under
you — the code is yours to edit.
- **Open registry.** Modules are plain static JSON. The CLI ships with a default
registry, but you can point it at your own host with `STANZA_REGISTRY` and
serve custom modules.
These docs are a work in progress. Use the sidebar to browse, or head to the
[builder](/) to start assembling a stack.
## How it fits together
You choose modules across a small set of **categories** — `framework`, `styling`,
`db`, `orm`, `auth`, `tooling`, `testing`. stanza scaffolds a clean monorepo,
vendoring each module's templates, dependencies, and environment variables into
the right place: app shell code into your app, data and auth layers into their
own workspace packages. Later, `stanza add` and `stanza remove` layer modules in
and out without you hand-editing the wiring.
## Next steps
- **[Getting started](/docs/getting-started)** — create your first project and add a module.
- **[Concepts](/docs/concepts)** — the mental model: categories, vendoring, peers, and the manifest.
- **[CLI reference](/docs/cli-reference)** — every verb, flag, and environment variable.
Or skip ahead and assemble a stack visually with the [builder](/).
+1 -1
View File
@@ -1,3 +1,3 @@
{
"pages": ["index", "getting-started", "cli-reference"]
"pages": ["index", "getting-started", "concepts", "cli-reference"]
}
+1 -1
View File
@@ -4,7 +4,7 @@ import { waitUntil } from "@vercel/functions";
import { getPostHogServerClient } from "@/server/posthog.server";
/**
* `POST /api/events` — analytics ingest for the `@stanza/cli`. The CLI sends
* `POST /api/events` — analytics ingest for the `stanza-cli`. The CLI sends
* plain `fetch` batches here so it never has to bundle `posthog-node`; this
* route holds the PostHog project key server-side and forwards each event via
* the `posthog-node` client.
+1 -1
View File
@@ -16,7 +16,7 @@
"fmt:check": "oxfmt --check",
"registry:build": "bun scripts/registry-build.ts",
"changeset": "changeset",
"release": "pnpm --filter @stanza/cli --filter create-stanza build && changeset publish"
"release": "pnpm --filter stanza-cli --filter create-stanza build && changeset publish"
},
"devDependencies": {
"@changesets/changelog-github": "^0.7.0",
+1 -1
View File
@@ -33,7 +33,7 @@
"check-types": "tsc --noEmit"
},
"dependencies": {
"@stanza/cli": "workspace:*"
"stanza-cli": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.9.1",
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env node
import { run } from "@stanza/cli";
import { run } from "stanza-cli";
import { version } from "../package.json" with { type: "json" };
+3 -3
View File
@@ -1,10 +1,10 @@
import { defineConfig } from "tsdown";
/**
* `create-stanza` is a thin shim over `@stanza/cli`. We compile its TS to
* ESM but externalize EVERYTHING — including `@stanza/cli` itself, which
* `create-stanza` is a thin shim over `stanza-cli`. We compile its TS to
* ESM but externalize EVERYTHING — including `stanza-cli` itself, which
* the user installs alongside `create-stanza` via npm's normal dep chain
* (it's in `dependencies`). Inlining `@stanza/cli` here would also pull in
* (it's in `dependencies`). Inlining `stanza-cli` here would also pull in
* its transitive 12 MB of ts-morph and friends.
*/
export default defineConfig({
+1 -1
View File
@@ -248,7 +248,7 @@ importers:
packages/create-stanza:
dependencies:
'@stanza/cli':
stanza-cli:
specifier: workspace:*
version: link:../../apps/cli
devDependencies:
+6 -6
View File
@@ -9,13 +9,13 @@ Use only the published CLI surface. Do not assume the Stanza source repo, local
## Runtime Contract
- The CLI package is `@stanza/cli`; the binary is `stanza`.
- The CLI package is `stanza-cli`; the binary is `stanza`.
- The create package is `create-stanza`; package-manager create commands forward to `stanza init`.
- Prefer direct npm execution in automation because it avoids package-manager argument-forwarding ambiguity:
```sh
npx -y @stanza/cli@latest --help
npx -y @stanza/cli@latest init my-app --yes --framework=next
npx -y stanza-cli@latest --help
npx -y stanza-cli@latest init my-app --yes --framework=next
```
- If the user wants create-style commands, use the correct separator for their package manager:
@@ -31,8 +31,8 @@ bun create stanza@latest my-app --yes --framework=next
1. Check the CLI surface before making assumptions:
```sh
npx -y @stanza/cli@latest --help
npx -y @stanza/cli@latest search
npx -y stanza-cli@latest --help
npx -y stanza-cli@latest search
```
2. Discover current module IDs with `stanza search [query]`. Registry contents evolve, so do not hardcode a module unless the user specified it or `search` confirms it.
@@ -40,7 +40,7 @@ npx -y @stanza/cli@latest search
3. Scaffold with `init --yes`, passing every category you want explicitly:
```sh
npx -y @stanza/cli@latest init my-app --yes \
npx -y stanza-cli@latest init my-app --yes \
--framework=next \
--styling=tailwind \
--db=postgres \