create-better-t-stack 3.22.3 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,8 +40,8 @@ Follow the prompts to configure your project or use the `--yes` flag for default
40
40
  | **ORM** | • Drizzle (TypeScript-first)<br>• Prisma (feature-rich)<br>• Mongoose (for MongoDB)<br>• None |
41
41
  | **Database Setup** | • Turso (SQLite)<br>• Cloudflare D1 (SQLite)<br>• Neon (PostgreSQL)<br>• Supabase (PostgreSQL)<br>• Prisma Postgres<br>• MongoDB Atlas<br>• None (manual setup) |
42
42
  | **Authentication** | Better-Auth (email/password, with more options coming soon) |
43
- | **Styling** | Tailwind CSS with shadcn/ui components |
44
- | **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Lefthook, Husky (Git hooks)<br>• Turborepo (optimized builds) |
43
+ | **Styling** | Tailwind CSS with a shared shadcn/ui package for React web apps |
44
+ | **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Lefthook, Husky (Git hooks)<br>• Turborepo or Nx (monorepo orchestration) |
45
45
  | **Examples** | • Todo app<br>• AI Chat interface (using Vercel AI SDK) |
46
46
  | **Developer Experience** | • Automatic Git initialization<br>• Package manager choice (npm, pnpm, bun)<br>• Automatic dependency installation |
47
47
 
@@ -56,10 +56,11 @@ Options:
56
56
  --template <type> Use a template (mern, pern, t3, uniwind, none)
57
57
  --database <type> Database type (none, sqlite, postgres, mysql, mongodb)
58
58
  --orm <type> ORM type (none, drizzle, prisma, mongoose)
59
+ --dry-run Validate configuration without writing files
59
60
  --auth <provider> Authentication (better-auth, clerk, none)
60
61
  --payments <provider> Payments provider (polar, none)
61
62
  --frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, astro, native-bare, native-uniwind, native-unistyles, none)
62
- --addons <types...> Additional addons (pwa, tauri, starlight, biome, lefthook, husky, ruler, mcp, turborepo, fumadocs, ultracite, oxlint, opentui, wxt, skills, none)
63
+ --addons <types...> Additional addons (pwa, tauri, starlight, biome, lefthook, husky, ruler, mcp, turborepo, nx, fumadocs, ultracite, oxlint, opentui, wxt, skills, none)
63
64
  --examples <types...> Examples to include (todo, ai, none)
64
65
  --git Initialize git repository
65
66
  --no-git Skip git initialization
@@ -77,6 +78,30 @@ Options:
77
78
  -h, --help Display help
78
79
  ```
79
80
 
81
+ ### Agent-Focused Commands
82
+
83
+ ```bash
84
+ # Raw JSON payload input (agent-friendly)
85
+ create-better-t-stack create-json --input '{"projectName":"my-app","yes":true,"dryRun":true}'
86
+ create-better-t-stack add-json --input '{"projectDir":"./my-app","addons":["wxt"],"addonOptions":{"wxt":{"template":"react"}}}'
87
+ create-better-t-stack create-json --input '{"projectName":"db-app","database":"postgres","orm":"drizzle","dbSetup":"neon","dbSetupOptions":{"mode":"manual"}}'
88
+
89
+ # Runtime schema/introspection output
90
+ create-better-t-stack schema --name all
91
+ create-better-t-stack schema --name createInput
92
+ create-better-t-stack schema --name addInput
93
+ create-better-t-stack schema --name addonOptions
94
+ create-better-t-stack schema --name dbSetupOptions
95
+ create-better-t-stack schema --name cli
96
+
97
+ # Local stdio MCP server
98
+ npx create-better-t-stack@latest mcp
99
+ ```
100
+
101
+ When you scaffold with the `mcp` addon, Better T Stack itself can also be installed into supported agent configs through `add-mcp` using a package runner command instead of assuming a global CLI install, for example `npx create-better-t-stack@latest mcp` or `bunx create-better-t-stack@latest mcp`.
102
+
103
+ For MCP project creation, prefer `install: false`. Long dependency installs can exceed common MCP client request timeouts, so the safest flow is to scaffold first and run your package manager install command afterward in the project directory.
104
+
80
105
  ## Telemetry
81
106
 
82
107
  This CLI collects anonymous usage data to help improve the tool. The data collected includes:
@@ -108,6 +133,12 @@ Create a project with default configuration:
108
133
  npx create-better-t-stack --yes
109
134
  ```
110
135
 
136
+ Validate a command without writing files:
137
+
138
+ ```bash
139
+ npx create-better-t-stack --yes --dry-run
140
+ ```
141
+
111
142
  Create a project with specific options:
112
143
 
113
144
  ```bash
@@ -6,32 +6,23 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
7
  var __exportAll = (all, no_symbols) => {
8
8
  let target = {};
9
- for (var name in all) {
10
- __defProp(target, name, {
11
- get: all[name],
12
- enumerable: true
13
- });
14
- }
15
- if (!no_symbols) {
16
- __defProp(target, Symbol.toStringTag, { value: "Module" });
17
- }
9
+ for (var name in all) __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true
12
+ });
13
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
18
14
  return target;
19
15
  };
20
16
  var __copyProps = (to, from, except, desc) => {
21
- if (from && typeof from === "object" || typeof from === "function") {
22
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
23
- key = keys[i];
24
- if (!__hasOwnProp.call(to, key) && key !== except) {
25
- __defProp(to, key, {
26
- get: ((k) => from[k]).bind(null, key),
27
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
28
- });
29
- }
30
- }
17
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
18
+ key = keys[i];
19
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
20
+ get: ((k) => from[k]).bind(null, key),
21
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
22
+ });
31
23
  }
32
24
  return to;
33
25
  };
34
26
  var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
35
-
36
27
  //#endregion
37
- export { __reExport as n, __exportAll as t };
28
+ export { __reExport as n, __exportAll as t };
package/dist/cli.mjs CHANGED
@@ -1,9 +1,293 @@
1
1
  #!/usr/bin/env node
2
- import "./command-handlers-Dvaw7W_l.mjs";
3
- import { createBtsCli } from "./index.mjs";
4
-
2
+ import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-COTG6r9y.mjs";
3
+ import z from "zod";
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ //#region src/mcp.ts
7
+ const ToolResponseSchema = z.object({
8
+ ok: z.boolean(),
9
+ data: z.any().optional(),
10
+ error: z.string().optional()
11
+ });
12
+ const McpCreateProjectInputSchema = types_exports.CreateInputSchema.safeExtend({
13
+ projectName: z.string().describe("Project name or relative path"),
14
+ frontend: z.array(types_exports.FrontendSchema).describe("Explicit frontend app surfaces. Do not use native frontends as styling options."),
15
+ backend: types_exports.BackendSchema.describe("Explicit backend framework"),
16
+ runtime: types_exports.RuntimeSchema.describe("Explicit runtime environment"),
17
+ database: types_exports.DatabaseSchema.describe("Explicit database choice"),
18
+ orm: types_exports.ORMSchema.describe("Explicit ORM choice"),
19
+ api: types_exports.APISchema.describe("Explicit API layer"),
20
+ auth: types_exports.AuthSchema.describe("Explicit authentication provider"),
21
+ payments: types_exports.PaymentsSchema.describe("Explicit payments provider"),
22
+ addons: z.array(types_exports.AddonsSchema).describe("Explicit addon list. Use [] when no addons are needed."),
23
+ examples: z.array(types_exports.ExamplesSchema).describe("Explicit example list. Use [] when no examples are needed."),
24
+ git: z.boolean().describe("Whether to initialize a git repository"),
25
+ packageManager: types_exports.PackageManagerSchema.describe("Explicit package manager"),
26
+ install: z.boolean().describe("Whether to install dependencies"),
27
+ dbSetup: types_exports.DatabaseSetupSchema.describe("Explicit database setup/provisioning choice"),
28
+ webDeploy: types_exports.WebDeploySchema.describe("Explicit web deployment choice"),
29
+ serverDeploy: types_exports.ServerDeploySchema.describe("Explicit server deployment choice"),
30
+ addonOptions: types_exports.AddonOptionsSchema.optional(),
31
+ dbSetupOptions: types_exports.DbSetupOptionsSchema.optional(),
32
+ directoryConflict: types_exports.DirectoryConflictSchema.optional()
33
+ }).describe("Explicit Better T Stack project configuration for MCP use. Provide the full stack config instead of relying on inferred defaults.");
34
+ function formatToolSuccess(data) {
35
+ return {
36
+ content: [{
37
+ type: "text",
38
+ text: JSON.stringify(data, null, 2)
39
+ }],
40
+ structuredContent: {
41
+ ok: true,
42
+ data
43
+ }
44
+ };
45
+ }
46
+ function formatToolError(error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ return {
49
+ content: [{
50
+ type: "text",
51
+ text: message
52
+ }],
53
+ structuredContent: {
54
+ ok: false,
55
+ error: message
56
+ },
57
+ isError: true
58
+ };
59
+ }
60
+ function getProjectToolAnnotations() {
61
+ return {
62
+ destructiveHint: true,
63
+ idempotentHint: false,
64
+ openWorldHint: true
65
+ };
66
+ }
67
+ function getMcpInstallTimeoutMessage(packageManager) {
68
+ return [
69
+ "MCP project creation requires `install: false`.",
70
+ "Dependency installation can exceed common MCP client request timeouts and cause the connection to close before the tool returns.",
71
+ `Scaffold the project first, then run \`${packageManager} install\` in the generated project directory from a terminal.`
72
+ ].join(" ");
73
+ }
74
+ function getStackGuidance() {
75
+ return {
76
+ workflow: [
77
+ "Call bts_get_schema or bts_get_stack_guidance before constructing a config if the request is ambiguous.",
78
+ "For project creation, build a full explicit config before calling bts_plan_project.",
79
+ "Always call bts_plan_project before bts_create_project.",
80
+ "Only call bts_create_project after the plan succeeds and matches the user's intent.",
81
+ "Use bts_plan_addons before bts_add_addons for existing projects."
82
+ ],
83
+ createContract: {
84
+ requiresExplicitFields: [
85
+ "projectName",
86
+ "frontend",
87
+ "backend",
88
+ "runtime",
89
+ "database",
90
+ "orm",
91
+ "api",
92
+ "auth",
93
+ "payments",
94
+ "addons",
95
+ "examples",
96
+ "git",
97
+ "packageManager",
98
+ "install",
99
+ "dbSetup",
100
+ "webDeploy",
101
+ "serverDeploy"
102
+ ],
103
+ optionalFields: [
104
+ "addonOptions",
105
+ "dbSetupOptions",
106
+ "directoryConflict"
107
+ ],
108
+ rule: "Do not call bts_plan_project or bts_create_project with a partial payload. MCP project creation requires the full explicit stack config."
109
+ },
110
+ fieldNotes: {
111
+ frontend: "frontend is for app surfaces only. Choose explicit app targets such as next, react-router, tanstack-router, native-bare, native-uniwind, or native-unistyles.",
112
+ addons: "addons must be an explicit array. Use [] when no addons are requested.",
113
+ examples: "examples must be an explicit array. Use [] when no examples are requested.",
114
+ dbSetup: "dbSetup is always required. Use 'none' when no managed database provisioning is requested.",
115
+ webDeploy: "webDeploy is always required. Use 'none' when no web deployment target is requested.",
116
+ serverDeploy: "serverDeploy is always required. Use 'none' when no server deployment target is requested.",
117
+ packageManager: "packageManager is always required because installation and reproducible commands depend on it.",
118
+ install: "install is always required. For MCP project creation, prefer false because many clients enforce request timeouts around long-running dependency installs.",
119
+ git: "git is always required. Set it to true or false explicitly instead of relying on defaults."
120
+ },
121
+ ambiguityRules: [
122
+ "If the user request leaves major stack choices unspecified, stop and resolve them before calling bts_plan_project.",
123
+ "Do not infer extra app surfaces, addons, examples, or provisioning choices from a template name or styling preference.",
124
+ "If the user wants the smallest valid stack, still send the full config with explicit 'none', [] , true, or false values where appropriate.",
125
+ "For MCP execution, scaffold with install=false and let the user or agent run dependency installation separately from a terminal session."
126
+ ]
127
+ };
128
+ }
129
+ function createBtsMcpServer() {
130
+ const server = new McpServer({
131
+ name: "create-better-t-stack",
132
+ version: getLatestCLIVersion()
133
+ }, { capabilities: { logging: {} } });
134
+ server.registerTool("bts_get_stack_guidance", {
135
+ title: "Get Better T Stack MCP Guidance",
136
+ description: "Read MCP-specific guidance for choosing valid Better T Stack configurations. Use this before planning when user intent is ambiguous. This explains the full explicit config required by MCP project creation, plus important field semantics and ambiguity rules.",
137
+ inputSchema: z.object({}),
138
+ outputSchema: ToolResponseSchema,
139
+ annotations: {
140
+ title: "Get Better T Stack MCP Guidance",
141
+ readOnlyHint: true,
142
+ destructiveHint: false,
143
+ idempotentHint: true,
144
+ openWorldHint: false
145
+ }
146
+ }, async () => {
147
+ try {
148
+ return formatToolSuccess(getStackGuidance());
149
+ } catch (error) {
150
+ return formatToolError(error);
151
+ }
152
+ });
153
+ server.registerTool("bts_get_schema", {
154
+ title: "Get Better T Stack Schemas",
155
+ description: "Inspect Better T Stack CLI and input schemas so agents can plan valid create/add requests. Use this together with bts_get_stack_guidance before creating a project if any part of the request is ambiguous.",
156
+ inputSchema: z.object({ name: SchemaNameSchema.optional().describe("Schema name to inspect. Defaults to all.") }),
157
+ outputSchema: ToolResponseSchema,
158
+ annotations: {
159
+ title: "Get Better T Stack Schemas",
160
+ readOnlyHint: true,
161
+ destructiveHint: false,
162
+ idempotentHint: true,
163
+ openWorldHint: false
164
+ }
165
+ }, async ({ name }) => {
166
+ try {
167
+ return formatToolSuccess(getSchemaResult(name ?? "all"));
168
+ } catch (error) {
169
+ return formatToolError(error);
170
+ }
171
+ });
172
+ server.registerTool("bts_plan_project", {
173
+ title: "Plan Better T Stack Project",
174
+ description: "Validate and preview a Better T Stack project creation without writing files or provisioning resources. Always use this before bts_create_project. This tool requires an explicit full stack config rather than a partial payload with inferred defaults.",
175
+ inputSchema: McpCreateProjectInputSchema,
176
+ outputSchema: ToolResponseSchema,
177
+ annotations: {
178
+ title: "Plan Better T Stack Project",
179
+ readOnlyHint: true,
180
+ destructiveHint: false,
181
+ idempotentHint: true,
182
+ openWorldHint: false
183
+ }
184
+ }, async (input) => {
185
+ try {
186
+ const result = await create(input.projectName, {
187
+ ...input,
188
+ dryRun: true,
189
+ disableAnalytics: true
190
+ });
191
+ if (result.isErr()) return formatToolError(result.error);
192
+ return formatToolSuccess(input.install ? {
193
+ ...result.value,
194
+ warnings: [getMcpInstallTimeoutMessage(input.packageManager)],
195
+ recommendedMcpExecution: {
196
+ ...input,
197
+ install: false
198
+ }
199
+ } : result.value);
200
+ } catch (error) {
201
+ return formatToolError(error);
202
+ }
203
+ });
204
+ server.registerTool("bts_create_project", {
205
+ title: "Create Better T Stack Project",
206
+ description: "Create a Better T Stack project on disk using the same silent programmatic flow as the CLI JSON API. Call this only after bts_plan_project succeeds and the plan clearly matches the user's intent. This tool requires an explicit full stack config.",
207
+ inputSchema: McpCreateProjectInputSchema,
208
+ outputSchema: ToolResponseSchema,
209
+ annotations: {
210
+ title: "Create Better T Stack Project",
211
+ ...getProjectToolAnnotations()
212
+ }
213
+ }, async (input) => {
214
+ try {
215
+ if (input.install) return formatToolError(getMcpInstallTimeoutMessage(input.packageManager));
216
+ const result = await create(input.projectName, {
217
+ ...input,
218
+ disableAnalytics: true
219
+ });
220
+ if (result.isErr()) return formatToolError(result.error);
221
+ return formatToolSuccess(result.value);
222
+ } catch (error) {
223
+ return formatToolError(error);
224
+ }
225
+ });
226
+ server.registerTool("bts_plan_addons", {
227
+ title: "Plan Better T Stack Addons",
228
+ description: "Validate and preview addon installation for an existing Better T Stack project without writing files. Always use this before bts_add_addons when the addon set or nested options are uncertain.",
229
+ inputSchema: types_exports.AddInputSchema,
230
+ outputSchema: ToolResponseSchema,
231
+ annotations: {
232
+ title: "Plan Better T Stack Addons",
233
+ readOnlyHint: true,
234
+ destructiveHint: false,
235
+ idempotentHint: true,
236
+ openWorldHint: false
237
+ }
238
+ }, async (input) => {
239
+ try {
240
+ const result = await add({
241
+ ...input,
242
+ dryRun: true
243
+ });
244
+ if (!result?.success) return formatToolError(result?.error ?? "Failed to plan addon installation");
245
+ return formatToolSuccess(result);
246
+ } catch (error) {
247
+ return formatToolError(error);
248
+ }
249
+ });
250
+ server.registerTool("bts_add_addons", {
251
+ title: "Add Better T Stack Addons",
252
+ description: "Install addons into an existing Better T Stack project using the same silent flow as add-json. Call this only after bts_plan_addons succeeds and the planned changes match the user's intent.",
253
+ inputSchema: types_exports.AddInputSchema,
254
+ outputSchema: ToolResponseSchema,
255
+ annotations: {
256
+ title: "Add Better T Stack Addons",
257
+ destructiveHint: true,
258
+ idempotentHint: false,
259
+ openWorldHint: true
260
+ }
261
+ }, async (input) => {
262
+ try {
263
+ const result = await add(input);
264
+ if (!result?.success) return formatToolError(result?.error ?? "Failed to add addons");
265
+ return formatToolSuccess(result);
266
+ } catch (error) {
267
+ return formatToolError(error);
268
+ }
269
+ });
270
+ return server;
271
+ }
272
+ async function startBtsMcpServer() {
273
+ const server = createBtsMcpServer();
274
+ const transport = new StdioServerTransport();
275
+ await server.connect(transport);
276
+ }
277
+ //#endregion
5
278
  //#region src/cli.ts
6
- createBtsCli().run();
279
+ const [, , command, ...args] = process.argv;
280
+ if (command === "mcp") {
281
+ if (args.includes("--help") || args.includes("-h")) {
282
+ console.log(`Usage: create-better-t-stack mcp
283
+
284
+ Start the Better T Stack MCP server over stdio.
7
285
 
286
+ This command is intended to be launched by an MCP client, for example:
287
+ create-better-t-stack mcp`);
288
+ process.exit(0);
289
+ }
290
+ await startBtsMcpServer();
291
+ } else createBtsCli().run();
8
292
  //#endregion
9
- export { };
293
+ export {};