-
Notifications
You must be signed in to change notification settings - Fork 20
Description
Overview
Add a btst init command to the @btst/cli package that automatically scaffolds all the boilerplate required to integrate BTST into an existing Next.js (App Router), React Router v7, or TanStack Start project.
The install docs currently require ~8 steps of manual file creation and surgical edits to existing files. This command automates the entire flow end-to-end — detecting the framework, picking the right adapter, installing dependencies, generating files, and patching the root layout and CSS.
Think shadcn/ui's npx shadcn init — a single command that gets a project from zero to working without consulting documentation.
npx @btst/cli init
# or if @btst/cli is already installed:
btst initCore Features
Framework Detection & Selection
- Auto-detect framework from
package.jsondeps (next,react-router,@tanstack/react-router) - Prompt to confirm or override when multiple frameworks are found
- Detect path alias convention from
tsconfig.jsonpaths (@/,~/, etc.) - Detect package manager from lockfile (
pnpm-lock.yaml,yarn.lock,package-lock.json)
Adapter Selection
- Interactive prompt to choose adapter:
memory,prisma,drizzle,kysely,mongodb - Install the corresponding
@btst/adapter-*package automatically
Dependency Installation
- Install
@btst/stackand@tanstack/react-queryvia detected package manager - Install selected
@btst/adapter-*package
File Generation
-
lib/query-client.ts— shared QueryClient utility (identical across frameworks) -
lib/stack.ts— backend instance with selected adapter boilerplate -
lib/stack-client.tsx— client instance stub (createStackClient) - Framework-specific API route handler:
- Next.js:
app/api/data/[[...all]]/route.ts - React Router:
app/routes/api/data/route.ts - TanStack:
src/routes/api/data/$.ts
- Next.js:
- Framework-specific page handler (catch-all):
- Next.js:
app/pages/[[...all]]/page.tsx - React Router:
app/routes/pages/index.tsx - TanStack:
src/routes/pages/$.tsx
- Next.js:
- Framework-specific
StackProviderlayout:- Next.js:
app/pages/[[...all]]/layout.tsx - React Router:
app/routes/pages/_layout.tsx - TanStack:
src/routes/pages/route.tsx
- Next.js:
Surgical File Patching
- Inject
@import \"@btst/stack/...\"into the project's global CSS file (auto-detected or prompted) - Wrap root layout / app entry with
<QueryClientProvider>— attempted via AST transform (ts-morph), with printed fallback instructions if the file is non-standard - Conflict handling for every generated file: skip / overwrite / show diff
Prerequisite Validation
- Warn (non-blocking) if
components.json(shadcn) is absent - Warn if Tailwind v4 is not detected in dependencies
- Warn if
<Toaster />(Sonner) is not present
Package Structure
packages/cli/
├── src/
│ ├── index.ts # commander entry — registers init + generate commands
│ ├── commands/
│ │ ├── init.ts # btst init — full project bootstrapping
│ │ └── generate.ts # btst generate — existing DB schema codegen
│ ├── templates/
│ │ ├── shared/
│ │ │ └── lib/query-client.ts # no templating needed; identical across frameworks
│ │ ├── nextjs/
│ │ │ ├── lib/stack.ts.hbs # Handlebars template, one variant per adapter
│ │ │ ├── lib/stack-client.tsx.hbs
│ │ │ ├── app/api/data/[[...all]]/route.ts.hbs
│ │ │ ├── app/pages/[[...all]]/page.tsx.hbs
│ │ │ └── app/pages/[[...all]]/layout.tsx.hbs
│ │ ├── react-router/
│ │ │ ├── lib/stack.ts.hbs
│ │ │ ├── lib/stack-client.tsx.hbs
│ │ │ ├── app/routes/api/data/route.ts.hbs
│ │ │ ├── app/routes/pages/index.tsx.hbs
│ │ │ └── app/routes/pages/_layout.tsx.hbs
│ │ └── tanstack/
│ │ ├── lib/stack.ts.hbs
│ │ ├── lib/stack-client.tsx.hbs
│ │ ├── src/routes/api/data/$.ts.hbs
│ │ ├── src/routes/pages/$.tsx.hbs
│ │ └── src/routes/pages/route.tsx.hbs
│ └── utils/
│ ├── detect-framework.ts # sniff package.json + folder layout
│ ├── detect-package-manager.ts # lockfile detection
│ ├── detect-alias.ts # read tsconfig.json paths
│ ├── detect-css-file.ts # find globals.css / app.css
│ ├── file-writer.ts # write + skip/overwrite/diff conflict UX
│ ├── package-installer.ts # run pnpm/npm/yarn add
│ ├── css-patcher.ts # inject @import line safely
│ └── layout-patcher.ts # ts-morph AST wrap for QueryClientProvider
├── package.json
├── tsconfig.json
└── build.config.ts
Command Interface
btst init [options]
Options:
--framework <name> Skip detection prompt (nextjs | react-router | tanstack)
--adapter <name> Skip adapter prompt (memory | prisma | drizzle | kysely | mongodb)
--skip-install Skip dependency installation
--cwd <path> Run in a different directory (default: process.cwd())
--yes Accept all defaults / overwrite all conflicts without prompting
-h, --help Show help
Interactive Prompt Flow
◆ Which framework are you using?
● Next.js (App Router)
○ React Router v7
○ TanStack Start
◆ Which database adapter?
● Memory (development / testing)
○ Prisma
○ Drizzle
○ Kysely
○ MongoDB
◆ Where is your global CSS file?
app/globals.css
Installing dependencies with pnpm...
+ @btst/stack
+ @tanstack/react-query
+ @btst/adapter-memory
Writing files...
✔ lib/query-client.ts
✔ lib/stack.ts
✔ lib/stack-client.tsx
✔ app/api/data/[[...all]]/route.ts
✔ app/pages/[[...all]]/page.tsx
✔ app/pages/[[...all]]/layout.tsx
Patching files...
✔ app/globals.css added @import \"@btst/stack/style.css\"
✔ app/layout.tsx wrapped children with QueryClientProvider
◆ All done!
Next steps:
→ Add plugins to lib/stack.ts and lib/stack-client.tsx
→ Generate database schema: npx @btst/cli generate --config=lib/stack.ts --orm=memory
→ Visit /pages to see plugin routes
Generated File Examples
lib/stack.ts (memory adapter, Next.js)
import { stack } from \"@btst/stack\"
import { createMemoryAdapter } from \"@btst/adapter-memory\"
let _stack: ReturnType<typeof stack> | undefined
function getStack() {
if (!_stack) {
_stack = stack({
basePath: \"/api/data\",
plugins: {
// Add your backend plugins here
},
adapter: (db) => createMemoryAdapter(db)({}),
})
}
return _stack
}
export const myStack = {
get handler() { return getStack().handler },
get api() { return getStack().api },
get adapter() { return getStack().adapter },
}lib/stack-client.tsx
import { createStackClient } from \"@btst/stack/client\"
import type { QueryClient } from \"@tanstack/react-query\"
export const getStackClient = (queryClient: QueryClient) =>
createStackClient({
plugins: {
// Add your client plugins here
},
})Detection Heuristics
| Signal | What it determines |
|---|---|
package.json dep: next |
Framework = Next.js |
package.json dep: react-router |
Framework = React Router |
package.json dep: @tanstack/react-router |
Framework = TanStack |
pnpm-lock.yaml present |
Package manager = pnpm |
yarn.lock present |
Package manager = yarn |
tsconfig.json paths @/* |
Alias = @/ |
tsconfig.json paths ~/* |
Alias = ~/ |
components.json absent |
Warn: shadcn not installed |
Layout Patching Strategy
The root layout patch (QueryClientProvider wrap) uses ts-morph to parse the TSX AST and find the JSX return value. If patching succeeds silently, great. If the file is non-standard (class component, unusual structure), the patcher prints a clear diff block with manual instructions rather than failing:
⚠ Could not automatically patch app/layout.tsx.
Add the following manually:
import { QueryClientProvider } from \"@tanstack/react-query\"
import { getOrCreateQueryClient } from \"@/lib/query-client\"
// Wrap your root {children} with:
<QueryClientProvider client={getOrCreateQueryClient()}>
{children}
</QueryClientProvider>
Non-Goals (v1)
- Scaffolding a brand-new framework project (wrapping
create-next-appetc.) — init targets existing projects only - Multi-monorepo-workspace awareness
- Adding plugins via
btst init(that is a separatebtst addcommand concern) - Windows-specific path handling beyond basic normalisation
- Non-TypeScript projects
Implementation Notes
- Use
@clack/promptsfor the interactive prompt UX (same as shadcn CLI) - Use
commanderfor argument parsing - Use
ts-morphfor AST-based layout patching - Use
handlebarsfor file templates (adapter × framework matrix) - Use
execafor running package manager commands - Build with
tsuporunbuild; ship as CJS + ESM with abinentry
Package Configuration
{
\"name\": \"@btst/cli\",
\"bin\": { \"btst\": \"./dist/index.cjs\" },
\"scripts\": {
\"build\": \"unbuild --clean\",
\"dev\": \"tsx src/index.ts\"
}
}Documentation
Add docs/content/docs/cli.mdx (or extend the existing CLI page) covering:
btst init— full walkthrough with animated terminal recording- Supported frameworks — Next.js, React Router, TanStack Start
- Supported adapters — all five, with links to adapter docs
--yesflag — CI/CD usage- Manual patching fallback — what to do when auto-patch fails
btst generate— existing schema generation docs (consolidate here)
Related Issues
- Existing
@btst/cli generatereferenced in installation docs —initlives in the samepackages/clipackage