- Update `@types/node`, `semver`, TanStack Router/Start, `posthog-node`, `shadcn`, `fumadocs-mdx`, and a handful of other minor dep bumps across the monorepo
- Upgrade pnpm to 11.5.2
- Replace deprecated `.inputValidator(…)` calls with `.validator(…)` on all server functions
- Rename the template file and update `src`/`dest` in the adapter's file list to match the new `proxy.ts` convention required by Next 16
- Update the example filename in `AGENTS.md` and `authoring.mdx` (`middleware.ts` → `proxy.ts`) so the scope guidance stays accurate
- Refactor `BarList` bar fill to animate `width` instead of `transform: scaleX` so the gradient and rounded cap don't distort; replace diagonal hatch overlay with a solid gradient + inset ring and tighten leading gap to `gap-1`
- Register a new `ai` category in `CATEGORIES` (cardinality `one`, home `packages/ai/`) so both modules land under the same single-choice slot
- Add `ai-vercel-ai-sdk`: installs `ai` + `@ai-sdk/openai`, emits a `model.ts` configured for `gpt-4o-mini`, a shared package entry-point, and a streaming `/api/chat` route for Next.js (`StreamingTextResponse`) and TanStack Start (`EventStream`); peers on `framework`
- Add `ai-tanstack-ai`: installs `@tanstack/ai` + `@tanstack/ai-openai`, emits an `adapter.ts` wrapping `openaiText("gpt-4o-mini")`, a shared entry-point, and a streaming `/api/chat` route for both frameworks via `toServerSentEventsResponse`; peers on `framework`
- Both modules declare `OPENAI_API_KEY` in `env` and ship provider-swap instructions in `readme.md`
- Update `registry.mdx` AI table: mark both modules 🟢 Available with short capability notes
- Add `declaredEnvNames(manifest)` to `@stanza/registry`: extracts a sorted, deduped list of env var names from `manifest.regions[".env.example"]` — the same keys the CLI records as modules apply; exported from the package index
- Add `env: string[]` to `TemplateContext` and an `envNames` option to `buildRenderContext`: sorts + dedupes the input so rendered output is stable regardless of module-apply order; defaults to `[]` when omitted
- Register a `{{json}}` Handlebars helper that `JSON.stringify`s any value (primary use: `"globalEnv": {{json env}}` in `turbo.json`, but generic enough for any template embedding a JS value into a JSON literal)
- Thread `envNames` through `codemod-runner`'s `renderContextFor` (derived from `declaredEnvNames(manifest)` so late-running repo-home modules like `monorepo-turbo` see all prior env claims) and through `synthesizeTemplates` + `synthesizeReadme` (aggregated from every resolved entry's merged install fields, matching what the CLI derives post-apply so CLI and web preview render identically)
- Update `monorepo-turbo/templates/turbo.json` to emit `"globalEnv": {{json env}}` so Turborepo task hashes track every project-wide env var; update `readme.md` to document the auto-population behavior
- Add `declaredEnvNames` tests (empty manifest, multi-key `.env.example` regions, non-env file regions ignored), `buildRenderContext` tests (sort+dedupe, omitted default), `{{json}}` helper tests (env array, empty array, missing key), and a `synthesizeTemplates` integration test verifying the aggregated env list flows into a rendered `turbo.json`
- Add `monorepo-turbo`: `turbo ^2.9.0` dev dep + a Handlebars-templated `turbo.json` at the repo root; module scripts (`dev`/`build`/`test`/`lint`) overwrite the pm-native fan-out defaults seeded by `rootPackageJson`; an `append-to-file` codemod adds `.turbo/` to `.gitignore` idempotently so both fresh `init` and `stanza add` projects are covered; light/dark logos inlined from svgl
- Add `pmRecursive(pm, script)` to `@stanza/registry` (and export it): produces the pm-native workspace-wide invocation (`pnpm -r run <s>`, `bun run --filter '*' <s>`, `npm run <s> --workspaces --if-present`); `rootPackageJson` now seeds all four root scripts via `pmRecursive` instead of hard-coding the pnpm form, and gains a `lint` entry that was previously missing
- Change `applyFields` script merging from guard-if-undefined to unconditional overwrite so a `monorepo` module's declared scripts can replace the seeded defaults; the same fix is applied to the `app`-overlay script path
- Fix `monorepo` category cardinality from `"many"` to `"one"` (only one task orchestrator makes sense per repo) and update its description
- Remove `.turbo/` from the hardcoded `.gitignore` written by `bootstrapShell` in `init.ts` — the module codemod now owns that entry
- Add `package-json.test.ts` coverage for `rootPackageJson` default scripts per pm and for monorepo module script overrides
- Add `email-resend`: `resend` SDK + `react-email` template in `packages/email/`; ships a shared `resend.ts` client, a sample `WelcomeEmail` component, and framework-native `/api/webhook/resend` Svix-verifier route handlers for Next.js and TanStack Start; light/dark logos inlined from svgl
- `RESEND_API_KEY` is required; `RESEND_WEBHOOK_SECRET` is optional and gates the webhook route
- Update `registry.mdx` resend row from 🟨 Planned to 🟢 Available with a feature summary
- Add `synthesizeReadme(resolved, ctx)` to `@stanza/registry`: generates a Markdown README from the assembled module selection using each module's `readme` / `description` copy; exported alongside new `Resolved` / `ResolvedEntry` types that capture the module + adapter pair after resolution
- Add `apps/cli/src/lib/readme.ts` with `writeFreshReadme` (used by `init` into a guaranteed-empty dir), `regenerateReadmeIfUnmodified` (used by `add`/`remove` to skip user-edited files), and `readmeChecksum` / `userModifiedReadme` helpers that compare SHA-256 against a new `readmeChecksum` field on `StanzaManifest`; a missing stored checksum with a present file is treated as user-owned (conservative, covers legacy projects)
- Wire README generation into all three commands: `init` calls `writeFreshReadme` after all modules apply and records the checksum; `add` and `remove` call `regenerateReadmeIfUnmodified` post-mutation and warn when the file has been edited; both update `stanza.json` with the new checksum on write
- Add `app` install-fields overlay in `codemod-runner.ts`: a per-module `installFields.app` bucket routes `dependencies`, `devDependencies`, and `scripts` into each consuming app's `package.json` rather than the workspace root or `packages/ui`; use case is package-home modules whose app-scoped shims import npm packages that belong in the app (e.g. `next-themes` for `ui-shadcn-*`); claims are recorded under `app.dependencies.<name>` region keys so removal can reverse them
- Fix `remove.ts` region handling: strip the `app.` prefix before dispatching `dependencies.*` / `devDependencies.*` / `scripts.*` removals so `app`-overlay claims are reversed correctly
- Add `pmRun(pm, script)` helper to `@stanza/registry` and use it in the `init` outro so the suggested dev command respects the project's package manager (e.g. `npm run dev` vs `pnpm dev`)
- Update `ui-shadcn-base` and `ui-shadcn-radix` module definitions to use the new `app` install-fields overlay for app-scoped peer deps; expand `package-json.test.ts`, `synthesize.test.ts`, and `template.test.ts` with coverage for the new paths
- Add `resolveExactVersion(name, version)` to `npm-version.ts`: wraps `resolveRange` with an implied `^${version}` range and strips the modifier from the result so callers get a bare pinned version suitable for Corepack; falls back to the input version on any lookup failure
- Rename the private `PM_VERSION` constant to `PM_FLOOR_VERSION` (exported from `@stanza/registry`) and store bare versions (no `${pm}@` prefix) so they can be fed directly into the resolver; the `rootPackageJson` helper now accepts an optional `packageManagerVersion` override and interpolates it into the `packageManager` field, falling back to the floor when absent
- Make `bootstrapShell` async in `init.ts` and call `resolveExactVersion` before writing `package.json` so newly-generated projects are pinned to the latest compatible release rather than a hardcoded floor; the web preview's synth path continues to use the floor as-is to avoid per-render npm lookups
- Add `resolveExactVersion` tests covering the happy path, `STANZA_NO_NPM_LOOKUP` bypass, network rejection fallback, and unsatisfied range fallback
- Rename `styling` → `ui` across the entire codebase (CATEGORIES array, docs, AGENTS.md, CLI tests, resolver, template tests, codemod runner); `ui` is `home: package` so shadcn installs into `packages/ui/` as a workspace dep rather than wiring directly into the app shell
- Add `ui-shadcn-base` (Tailwind v4 / CSS-first, no Radix peer) and `ui-shadcn-radix` (Tailwind v4 + Radix primitives) with full per-framework template sets for Next.js and TanStack Start: `components.json`, `globals.css`, `postcss.config.mjs`, `theme-provider.tsx`, shared `Button` + `utils.ts`; light/dark logos inlined from svgl
- Rename `styling-tailwind` → `ui-tailwind` to match the new category id; update its module definition to `category: "ui"` and `home: package`
- Add four new codemod builtins with tests: `add-array-entry-in-call` (inserts an element into a named array argument of any `CallExpression`), `replace-import` (rewrites a specifier in an existing import declaration), `set-html-attributes` (sets attributes on an HTML/JSX element by tag name or selector), `set-tsconfig-paths` (merges `compilerOptions` entries into a `tsconfig.json` AST node); register all four in the builtins index and export from `@stanza/codemods`
- Add `wrap-root-layout` builtin tests
- Update registry.mdx, concepts.mdx, cli.mdx, getting-started.mdx, agents.mdx, index.mdx, AGENTS.md, README.md, TODO.md, and SKILL.md to reflect the category rename and new modules
- Add `payments-stripe`: `stripe` SDK + framework-native Checkout Session / webhook route handlers for Next.js and TanStack Start; Better Auth bridge variant ships `@better-auth/stripe` and wires the plugin into `auth.ts` when `auth: better-auth` is selected; light logo inlined from svgl
- Sync the web builder's open file to the URL hash so refreshes and shared links restore the same selection; latch the last file path so folder-expand clicks don't wipe the preview; back/forward navigation reflects hash changes back into the tree; default-file selections don't pollute the hash (keeps shareable URLs clean)
- Trim over-explained JSDoc comments in `add-package-dep.ts` and `add-plugin-to-call.ts` to the terse one-liner style; condense the `init.ts` `fullPending` comment to match
- Update `registry.mdx` stripe row from 🟨 Planned to 🟢 Available with a brief feature summary
- Replace per-framework template files (`eslint.config.next.mjs`, `eslint.config.tanstack.mjs`) with a single `eslint.config.mjs` that branches via Handlebars `{{#if peers.framework}}` conditionals; add `handlebars` as a direct dependency to `@stanza/registry`, `apps/cli`, and `apps/web`
- Extend the template render context with a `peers: Partial<Record<CategoryId, string>>` map so any template can inspect the active framework, auth provider, etc.; thread it through `buildRenderContext`, `synthesizeTemplates`, the CLI `codemod-runner`, and the web `getBuilderState` server function
- Extract and export `activePeerIds(manifest, appId?)` from `@stanza/registry` to derive the peer map from a manifest (app-scoped for `home: app` categories); add `selectedPeerIds(selections)` in `apps/web/src/lib/selection.ts` as the URL-params-derived equivalent
- Add integration tests verifying framework-conditional eslint-prettier output for `default`, `next`, and `tanstack-start` adapters; expand resolver tests for `activePeerIds` app-scoping and for modules that declare both a `default` adapter and a framework-specific override
- Add `payments-polar`: `@polar-sh/sdk` + framework-native checkout/webhook route handlers for Next.js and TanStack Start; Better Auth bridge variant ships `@polar-sh/better-auth` and wires the plugin into `auth.ts` when `auth: better-auth` is selected; light/dark logos inlined from svgl
- Consolidate the registry build: delete `scripts/registry-build.ts` and move the emit logic into `packages/registry/src/build.ts`, which now accepts an optional positional output-base arg (defaults to `dist/`) and writes `{base}/registry/{index,modules/*}.json` + `{base}/schema.json` directly; `prepare-registry.sh` is reduced to a single `jiti packages/registry/src/build.ts apps/web/public` invocation; CI/release workflows drop the Bun setup + `registry:build` steps since the build now runs inline at web-app prebuild time
- Replace `add-vite-plugin` codemod with the more general `add-plugin-to-call` (targets any `CallExpression` by callee + arg position, not just `vite.config` `plugins` arrays); add `add-package-dep` builtin for imperatively injecting deps into a `package.json` AST node; both are fully tested and registered in the builtins index
- Fix `init` adapter resolution order: precompute a `fullPending` map from all peer-category picks before the apply loop so `resolveAdapter` sees the complete peer set regardless of `categoryOrder` traversal sequence; export `PEER_CATEGORIES` from `@stanza/registry` to support this
- Introduce `AppSpec` (`{ id, dir, kind }`) and `AppKind = "web" | "native"` types; `stanza.json` now declares `apps: AppSpec[]` alongside modules, and `stanza init` scaffolds a default web app via `defaultWebApp()`
- Add optional `apps?: string[]` to `StanzaModuleRecord` to encode which apps a record targets; `home: app` modules require it, `home: package` modules use it to scope workspace deps (omitting means all apps), `home: repo` modules forbid it
- Make cardinality enforcement app-scoped for `home: app` categories: `selectedOne(m, cat, appId?)` and `selectedAll(m, cat, appId?)` now filter by app, and `add`/`remove` thread a `targetApp` through the runner so per-app single-choice rejection works correctly
- Extend the template render context with an `app: { id, dir, kind }` binding (plus the legacy `project.appDir` alias) re-bound per target app; the codemod runner fans out template/codemod/dep application once per consuming app in a loop
- Update `synthesizePackageJsons`, `synthesizeTemplates`, `buildRenderContext`, and related web-preview helpers to accept an `apps` array and produce per-app output
- Update `package-json.ts` to strip workspace deps from all apps' `package.json` on remove and to inject them into every consuming app on install
- Expand `manifest.test.ts` and `template.test.ts` with multi-app fixture coverage; add `"use client"` directive to codemod test files to satisfy the RSC boundary
- Refresh `AGENTS.md`, `SKILL.md`, and all affected docs (`concepts.mdx`, `registry.mdx`, `cli.mdx`, `getting-started.mdx`, `agents.mdx`) to document the new apps schema and routing semantics
- Promote `renderTemplate` and `buildRenderContext` from `@stanza/codemods` into `@stanza/registry` alongside `synthesizeManifest`/`synthesizeEnvExample`/`synthesizePackageJsons`; add a new `synthesizeTemplates` export that returns the fully-substituted file list for a resolved selection so the web preview and the CLI apply path share identical logic
- Change the template DSL to dotted paths: `{{project.name}}` (was `{{projectName}}`), `{{project.appDir}}` (was `{{appDir}}`), `{{package.name}}` (was `{{packageName}}`), and `{{packages.<dir>.name}}` (was `{{<dir>PackageName}}`, e.g. `{{packages.db.name}}`); add a `TemplateContext` type exported from `@stanza/registry`
- Migrate all first-party modules (`auth-better-auth`, `auth-clerk`) to the new dotted syntax; fixes the web builder preview regression where tokens like `{{dbPackageName}}` appeared unsubstituted
- Update AGENTS.md docs and CLI `codemod-runner.ts` to reflect the new context shape and import locations
- Add a `tanstack-start` adapter to `auth-clerk` with `@clerk/tanstack-react-start` dependency, env vars, and templates (`provider.tsx`, `index.ts`, `start.ts`)
- Reorganize existing Next.js templates into a `next/` subdirectory and update `module.ts` src paths accordingly
- Update peers from `["next"]` to `["next", "tanstack-start"]` and reflect the completed TanStack Start support in the registry docs
- Delete `components/copy-button.tsx` and replace it with `components/ui/copy-button.tsx`; the new version is a proper shadcn-style primitive that uses the enhanced `Tooltip` for its label and fires an `onCopy` callback after a successful write
- Add `components/ui/copyable-field.tsx` — a composable field that pairs a monospace text display with the new `CopyButton` in a single bordered row; `CommandPreview` now delegates to `CopyableField` instead of managing its own `<pre>` + icon button
- Add `hooks/use-pointer-capability.ts` — a `matchMedia(pointer: fine)` hook that distinguishes touch-only devices from mouse/stylus inputs; used to conditionally suppress hover-only affordances
- Expand `components/ui/tooltip.tsx` with a `nativeButton` prop on `TooltipTrigger` and better composability; use it in `slot-cards.tsx` to show disabled-card reasons as a tooltip instead of appending inline muted text below the card
- Expand `components/ui/scroll-area.tsx` with scrollbar-corner and horizontal scrollbar sub-components so the primitive is fully composable
- Add icons (sun / moon / laptop) to `ModeToggle` dropdown items; make the GitHub header button `size="icon"` and inline the anchor JSX; rename the detail-page "Try it" heading to "Install"
- Replace the `active && "bg-muted"` conditional class in `SiteSearch` results with a plain `hover:bg-muted` rule; remove `no-scrollbar` from the results list so native scrollbars reappear on pointer devices
- Replace the `slot` / `add-on` discriminated-union split with one `Category` shape carrying two orthogonal fields: `cardinality` (`"one"` for single-choice, `"many"` for coexisting) and `home` (`"app"` / `"repo"` / `"package"`) — the old `packageDir` + `repoScoped` pair is dropped
- `Module` is no longer a discriminated union; it carries a single `category` field referencing a `Category` id; `KNOWN_SLOTS`, `KNOWN_ADDONS`, `ADDON_CATEGORIES`, and all related helpers are replaced by a single `CATEGORIES` array and derived `categoryHome` / `categoryLabel` / `PACKAGE_DIRS` lookups
- Manifest schema bumped to version `0.2` — `modules` is now one record keyed by category holding arrays; `cardinality: "one"` categories are enforced to ≤ 1 entry at install time; no migration (stanza is pre-1.0 and unpublished)
- Peer/constraint logic is now emergent from cardinality: the resolver treats only `cardinality: "one"` categories as peers, so `testing` (many) can never accidentally become a peer; install routing is a single `categoryHome` lookup shared by the CLI runner, codemod runner, and web preview
- Update all CLI commands (`add`, `remove`, `init`, `list`, `search`), the wizard, `codemod-runner`, `registry-loader`, all web builder/detail/search components, server functions, OG route, sitemap, analytics, and selection logic to use the new category API
- Update all first-party `module.ts` files, `registry-build.ts`, tests, and docs (`AGENTS.md`, `REGISTRY.md`, `SKILL.md`) to reflect the unified taxonomy
- Wrap `setSelection` and `toggleAddon` in `startTransition` + `useOptimistic` so card borders and checkmarks flip instantly on click; the preview pane continues to wait on committed loader data (server-rendered Shiki HTML) and shows its own spinner for that round-trip
- Fire-and-forget `getHighlighter()` during the initial `getBuilderState` call so the Shiki singleton is warm before the first slot toggle, eliminating cold-start latency on the first preview render
- Fix `initialExpandedPaths` replay in `FilePreview`: filter the expanded-dir set to only directories whose entire ancestor chain is also expanded, preventing a collapsed parent from being re-opened when its still-flagged descendant is replayed
- Hoist the loading overlay outside the empty/non-empty branch so it also covers the initial `filePaths === []` → content transition, where `filePaths` is still stale while the loader is in flight
- Promote `tooling` from an add-on category to a single-choice **slot** in `KNOWN_SLOTS`/`SLOTS` and remove it from `KNOWN_ADDONS`/`ADDON_CATEGORIES`; the three toolchains are mutually exclusive substitutes so single-choice semantics fit, and nothing peers on `tooling` so it bears no outbound dispatch constraints
- Add `registry/modules/tooling-eslint-prettier` — ESLint flat config + Prettier with per-framework adapters (`next` → `eslint.config.next.mjs`; `tanstack-start` → `eslint.config.tanstack.mjs`) and a shared `prettier.config.mjs`; scripts: `lint: "eslint ."`, `format: "prettier --write ."`
- Add `registry/modules/tooling-biome` — Biome 2.x with a single `default` adapter (framework-agnostic `biome.json`); scripts: `lint`, `format`, `check`
- Add `registry/modules/tooling-oxlint-oxfmt` — Oxlint + oxfmt with a single `default` adapter (`dot_oxlintrc.json`, `dot_oxfmtrc.json`); scripts: `lint`, `format`
- Drop `lint: "next lint"` from `framework-next` — `next lint` was removed in Next 16, so the tooling module now owns `scripts.lint` cleanly
- Add CLI tests covering `init --yes --tooling eslint-prettier`, framework-next shipping no lint script without a tooling pick, `add tooling biome` on an existing project, and slot-already-filled rejection
- Introduce a `kind: "slot" | "addon"` discriminated union on `Module` — slot modules carry `slot`, add-on modules carry `category` (one of `KNOWN_ADDONS`). `isAddon()` narrows the union; `moduleGroup()` returns the slot-or-category key. Add-on categories (`testing`, `tooling`, `deploy`, `email`, `monorepo`) live in `KNOWN_ADDONS`/`ADDON_CATEGORIES`, deliberately disjoint from `KNOWN_SLOTS` so the resolver never lets add-ons participate in peer dispatch (they can still declare a one-way `peers` + per-framework adapters)
- Ship the first two add-ons: `testing-vitest` (jsdom + RTL, `test`/`test:watch` scripts, per-framework adapters) and `testing-playwright` (per-framework `webServer`, `test:e2e`/`test:e2e:ui` scripts — disjoint from vitest's so region claims don't collide); both under `registry/modules/testing-*/`
- Manifest gains `addons: Partial<Record<AddonCategoryId, StanzaAddonRecord[]>>` (`.default({})` keeps existing `stanza.json` valid); resolver gains `addonOrder` for deterministic codemod sequencing
- CLI: `stanza add <slot|category> <module>` accepts both slots and add-on categories; duplicate-id guard for add-ons instead of the single-fill slot guard; `stanza remove <slot|category> [id]` removes a specific add-on by id (or the whole slot); `stanza list` shows add-ons alongside slots; `stanza init --yes` gains `--testing vitest,playwright` flag; wizard prompts multi-select for add-on categories
- Web builder: add-on slots render as checkbox multi-select cards (`SlotSection` detects `isAddon` and switches to `<CheckboxCard>`), `?testing=vitest,playwright` comma-joined URL param, `builder-state.functions.ts` parses/serializes per-category add-on lists, OG and sitemap routes updated for add-on module paths
- Codemod runner branches on `isAddon` to resolve add-on records from `manifest.addons[category]` rather than `manifest.modules[slot]`; region ownership keys on `module.id` so co-existing add-ons writing the same file at disjoint dot-paths never conflict
- Add `commands.test.ts`, `selection.test.ts`, `manifest.test.ts`, and `resolver.test.ts` coverage for add-on add/remove/list flows and schema validation
- `framework-tanstack-start` now ships `src/globals.css` as a first-class template (base styles: reset, system font stack, centred `<main>`) and `__root.tsx` imports it directly — CSS was previously written by `styling-tailwind` but never consumed, causing it to be orphaned on disk
- `styling-tailwind`'s tanstack-start adapter drops its `templates` entry and switches to the same `append-to-file { position: "start" }` pattern as the next adapter — prepends `@import "tailwindcss";` before existing base styles, revert is clean, `@import` order is guaranteed; both framework adapters are now structurally identical
- Delete `scripts/module-new.ts` — scaffolding helper no longer used or maintained
- Remove `posthog-node` from `apps/cli` dependencies — telemetry is unimplemented; drop it until the feature is actually wired
- Remove `@clack/prompts`, `kleur`, `mri` from root `package.json` devDependencies — these belong to `apps/cli` and were redundant at the root level
- Mark two TODO items done: tanstack-start globals.css orphan and `auth-better-auth` VITE_BETTER_AUTH_URL (stale — auth-client defaults to current origin, no template references it)
- `append-to-file` gains `position: "start"` to prepend the wrapped block before existing file content — required for CSS `@import "tailwindcss"` which must precede all other rules; `leadingBlank` becomes a trailing-blank control in prepend mode; revert strips the injected block cleanly in both directions; three new test cases (prepend order, revert, idempotency)
- `styling-tailwind` next adapter switches from writing `app/globals.css` as a template to prepending `@import "tailwindcss";` via `append-to-file { position: "start" }` — framework retains ownership of base styles, merge order is guaranteed, revert restores cleanly
- `auth-better-auth` drizzle templates split from a single `auth.drizzle.ts` into `auth.drizzle.postgres.ts` + `auth.drizzle.sqlite.ts` so each passes the correct `provider: "pg"` or `provider: "sqlite"` to `drizzleAdapter`; module adapter updated to select the right template based on the active orm peer
- Inline `defaultPmVersion` (init.ts), `summarize` (registry-loader.ts), `cancel` (wizard.ts), and `openViteConfig`/`relPath` (add-vite-plugin.ts) helpers — each was called exactly once; removing the indirection makes the call sites self-contained
- Mark two TODO items as done: per-db drizzle template split and styling-tailwind globals.css merge order
- Replace parallel `KNOWN_SLOTS` tuple, `slotOrder` array, and `SLOT_PACKAGE_DIR` map with a single `SLOTS: Slot[]` constant — each entry carries `{ id, label, description, packageDir }`; `KNOWN_SLOTS` is re-derived as `SLOTS.map(s => s.id) as const` for Zod literal inference; `slotLabel` and the package-dir lookup both become simple lookups over the same array; adding a slot is now a two-line edit
- Hoist `dependencies`, `devDependencies`, `env`, and `scripts` to the module level on `ModuleAdapter`'s parent `Module` type — adapter-level values still override per-key; avoids re-declaring the same dep/env block in every adapter (e.g. Better Auth's `better-auth` dep and two env vars are now declared once at module level while per-framework templates and codemods stay in their adapter blocks)
- Rename `peerPackages` → `consumesPackages` and lift it from adapter scope to module scope — cross-package imports are shared infrastructure that doesn't vary per adapter; runner wires `@<project>/<dir>: workspace:*` once per module install rather than once per adapter
- Update all first-party modules (`auth-better-auth`, `orm-drizzle`, `orm-prisma`, `framework-next`, `framework-tanstack-start`, `styling-tailwind`) to the new schema
- Update CLI (`codemod-runner`, `registry-loader`, `wizard`, `add`, `init`) and `scripts/registry-build.ts` to consume the new `SLOTS` array and hoisted module fields
- Update `apps/web/scripts/copy-registry.ts` and docs (`CLAUDE.md`, `REGISTRY.md`, `README.md`, `TODO.md`) to reflect the consolidated model and clarify the slots-vs-add-ons taxonomy
- Delete `packages/internal` workspace package — `registry-build.ts` and `module-new.ts` move to top-level `scripts/` (no `package.json`, not shipped); `pnpm registry:build` and `pnpm module:new` scripts updated in root `package.json` and `turbo.json`; CLAUDE.md / TODO.md references updated
- Relocate CLI internals from `apps/cli/src/` → `apps/cli/src/lib/` — `codemod-runner.ts`, `manifest.ts`, `region-tracker.ts`, `registry-loader.ts`, `wizard.ts`; all intra-CLI imports updated to `@/lib/*` path alias via tsconfig `paths`; add `@types/bun` to CLI devDependencies
- `stanza remove` now dispatches `revertCodemods()` as step 1 (before declarative cleanup) — re-loads the module adapter from the registry, calls imperative reverts while framework files are still intact, then sweeps remaining region claims; fixes `wrap-root-layout` / `re-export` regions previously left as "needs manual cleanup" despite shipping working reverts
- Add `SLOT_PACKAGE_DIR` map to `packages/registry/src/module.ts`: `auth → "auth"`, `db`+`orm → "db"`, `framework`+`styling → null` (app-scoped); drives where package-scoped templates and deps land
- Runner gains `ensureSlotPackage` — bootstraps `packages/<dir>/package.json` + `tsconfig.json` on first install and merges adapter `dependencies`/`devDeps`/`scripts` there; wires the app to the slot package via a `workspace:*` dep
- Add `scope: "package"` to `TemplateRef` — resolves dest against `packages/<SLOT_PACKAGE_DIR[slot]>/` instead of `appDir` or repo root; runner writes package-scoped files to the right home
- Add `peerPackages` to `ModuleAdapter` — declares cross-package deps (e.g. `auth` needing `db`); runner injects `@<project>/<dir>: workspace:*` into the current package's `package.json`
- Add `{{<dir>PackageName}}` mustache substitution (e.g. `{{dbPackageName}}` → `@my-app/db`) — runs over template bodies (`template: true`) and codemod `args` string values; enables auth templates to import from the db package without hardcoding names
- Add `base: "package:<dir>"` support to `re-export` and `append-to-file` builtins — codemods can target files inside another slot's package (e.g. extending the orm schema barrel from the auth module)
- Update `auth-better-auth`, `auth-clerk`, `orm-drizzle`, `orm-prisma` modules to use `scope: "package"` templates and `peerPackages` cross-wiring; rename `layout-wrapper.tsx` → `provider.tsx` in auth-clerk
- `stanza remove` updated to sweep `packages/<dir>/` when no region claims remain under it
- Update `selection.ts` in apps/web to account for package-scoped file paths
- Document extraction model, `SLOT_PACKAGE_DIR`, authoring rules, and `base:` codemod targeting in `CLAUDE.md`, `README.md`, and `REGISTRY.md`
- `append-to-file`: text-level append primitive that wraps inserted blocks with `stanza:<marker>:start/end` marker comments — idempotent on re-apply, fully revertible, comment style auto-inferred from file extension (line/hash/block); designed for Prisma schemas, CSS, YAML, and other non-TS files where AST codemods are overkill
- `re-export`: AST builtin for adding named or wildcard re-exports to an existing barrel/index file
- export both from `builtins/index.ts` and the top-level `src/index.ts`
- wire `auth-better-auth/module.ts` to use the new builtins via catalog invocations
- Modules no longer ship codemod code; adapters now declare `codemods: [{ id, args }]` referencing catalog entries by id — the registry stays pure data
- Add `apps/cli/src/codemods/` catalog: `wrap-root-layout` codemod (parameterized by provider import, component name, etc.) + `CODEMOD_CATALOG` map statically imported into the CLI binary so distribution shape (single binary, npx, bun compile) doesn't matter
- Remove `loadCodemods`, `getBundleCacheDir`, and all `codemodBundle` write/import machinery from `codemod-runner.ts`; runner now dispatches via `CODEMOD_CATALOG[invocation.id]` and forwards `invocation.args`
- Drop `registry-build.ts` codemod bundling step and `mod.codemodBundle` field from the registry package; remove per-module `codemods/index.ts` (auth-clerk replaced by catalog invocation with args)
- Change `ModuleAdapter.codemods` type from `string[]` to `CodemodInvocation[]` (`{ id: string; args?: Record<string, unknown> }`)
- Update `CLAUDE.md` to document "Registry is data; CLI is the runtime" principle and the process for adding/invoking generic codemods
- **Module logos**: `registry-build.ts` now auto-detects `logo.svg` / `logo-light.svg` + `logo-dark.svg` in each module directory and inlines them as `mod.logo` (string or `{ light, dark }`) — no `module.ts` declarations needed; first-party SVGs added for all current modules
- **Codemod bundling**: `registry-build.ts` bundles each module's `codemods/index.ts` via `Bun.build` (ESM, externals: `@stanza/codemods`, `ts-morph`, `node:*`) and embeds the output as `mod.codemodBundle`; the CLI runner materializes it to `node_modules/.cache/stanza-codemods/` so externals resolve normally, replacing the old "first-party only" approach
- **Web builder UI**: split monolithic `builder.tsx` into `builder/{index,slot-cards,command-bar,file-preview}.tsx`; add `Header`, `Footer`, `ModeToggle`, `ThemeProvider`; scaffold shadcn `Badge`, `Card`, `DropdownMenu`, `Input`, `Separator`, `Sonner`, `Tabs`, `Tooltip` components
- **Server-side Shiki**: `apps/web/src/server/highlighter.ts` keeps a warm Shiki instance; `builder-state.ts` (`createServerFn`) computes selections from URL params and pre-renders `{ light, dark }` HTML per file — Shiki is never imported client-side
- **Selection logic**: new `apps/web/src/lib/selection.ts` with full unit tests
- **copy-registry script**: `predev`/`prebuild` hook copies `dist/registry/` → `apps/web/public/registry/` so the same-domain registry path resolves without a separate CDN
- Add `shiki`, `sonner`, `@pierre/trees`, `@fontsource-variable/geist-mono` to `apps/web`; update oxfmt ignore patterns and swap `react-hooks` for `react-perf` + `promise` in oxlint web config
- configure Tailwind v4 via `@tailwindcss/vite` with a full CSS variable theme (light/dark) and Geist Variable font
- add shadcn `components.json` (base-lyra style, tabler icons) and scaffold `Button` component using `@base-ui/react`
- wire in `TanStackDevtools` + `TanStackRouterDevtoolsPanel` in the root layout
- switch path alias from `~/` to `@/` across tsconfig, routes, and components
- add `clsx`/`tailwind-merge` `cn` utility, `vitest`, `prettier-plugin-tailwindcss`, and other supporting deps
- split better-auth drizzle adapters into separate postgres/sqlite variants with a dedicated sqlite schema template
- simplify auth-client templates to use `createAuthClient()` without an explicit baseURL
- export `Node` type and `SyntaxKind` enum from the codemods package
- add codemod for the auth-clerk module