@tanstack/cli 0.0.1

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/dist/bin.mjs ADDED
@@ -0,0 +1,469 @@
1
+ #!/usr/bin/env node
2
+ import { A as writeConfigFile, a as initIntegration, d as fetchManifest, i as compileIntegration, j as compile, n as initTemplate, r as loadTemplate, t as compileTemplate, u as fetchIntegrations } from "./template-2SxOxCJc.mjs";
3
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ import { z } from "zod";
6
+ import { Command } from "commander";
7
+ import { cancel, confirm, intro, isCancel, log, multiselect, note, outro, select, spinner, text } from "@clack/prompts";
8
+ import chalk from "chalk";
9
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
12
+ import express from "express";
13
+
14
+ //#region src/commands/create.ts
15
+ const PACKAGE_MANAGERS = [
16
+ "pnpm",
17
+ "npm",
18
+ "yarn",
19
+ "bun",
20
+ "deno"
21
+ ];
22
+ function detectPackageManager() {
23
+ const userAgent = process.env.npm_config_user_agent;
24
+ if (userAgent) {
25
+ if (userAgent.includes("pnpm")) return "pnpm";
26
+ if (userAgent.includes("yarn")) return "yarn";
27
+ if (userAgent.includes("bun")) return "bun";
28
+ if (userAgent.includes("deno")) return "deno";
29
+ }
30
+ return "npm";
31
+ }
32
+ function validateProjectName(name) {
33
+ if (!name) return {
34
+ valid: false,
35
+ error: "Project name is required"
36
+ };
37
+ if (!/^[a-z0-9-_]+$/.test(name)) return {
38
+ valid: false,
39
+ error: "Project name can only contain lowercase letters, numbers, hyphens, and underscores"
40
+ };
41
+ return { valid: true };
42
+ }
43
+ function groupIntegrationsByCategory(integrations) {
44
+ const groups = {};
45
+ for (const integration of integrations) {
46
+ const category = integration.category ?? "other";
47
+ groups[category] ??= [];
48
+ groups[category].push(integration);
49
+ }
50
+ return groups;
51
+ }
52
+ const CATEGORY_LABELS = {
53
+ tanstack: "TanStack",
54
+ database: "Database",
55
+ orm: "ORM",
56
+ auth: "Authentication",
57
+ deploy: "Deployment",
58
+ tooling: "Tooling",
59
+ monitoring: "Monitoring",
60
+ api: "API",
61
+ i18n: "Internationalization",
62
+ cms: "CMS",
63
+ other: "Other"
64
+ };
65
+ const CATEGORY_ORDER = [
66
+ "tanstack",
67
+ "database",
68
+ "orm",
69
+ "auth",
70
+ "deploy",
71
+ "api",
72
+ "monitoring",
73
+ "tooling",
74
+ "i18n",
75
+ "cms",
76
+ "other"
77
+ ];
78
+ async function runCreate(projectName, options) {
79
+ intro(chalk.bgCyan(chalk.black(" TanStack Start ")));
80
+ const s = spinner();
81
+ const integrationsPath = options.integrationsPath;
82
+ s.start("Fetching available integrations...");
83
+ let manifest;
84
+ try {
85
+ manifest = await fetchManifest(integrationsPath);
86
+ s.stop("Integrations loaded");
87
+ } catch (error$1) {
88
+ s.stop("Failed to fetch integrations");
89
+ log.error("Could not fetch integration manifest. Check your internet connection.");
90
+ process.exit(1);
91
+ }
92
+ let name = projectName;
93
+ if (!name && !options.yes) {
94
+ const nameInput = await text({
95
+ message: "Project name:",
96
+ placeholder: "my-tanstack-app",
97
+ defaultValue: "my-tanstack-app",
98
+ validate: (value) => {
99
+ const result = validateProjectName(value);
100
+ return result.valid ? void 0 : result.error;
101
+ }
102
+ });
103
+ if (isCancel(nameInput)) {
104
+ cancel("Operation cancelled.");
105
+ process.exit(0);
106
+ }
107
+ name = nameInput;
108
+ }
109
+ name = name ?? "my-tanstack-app";
110
+ const { valid, error } = validateProjectName(name);
111
+ if (!valid) {
112
+ log.error(error ?? "Invalid project name");
113
+ process.exit(1);
114
+ }
115
+ const targetDir = options.targetDir ? resolve(options.targetDir) : resolve(process.cwd(), name);
116
+ if (existsSync(targetDir)) {
117
+ if (!options.yes) {
118
+ const overwrite = await confirm({
119
+ message: `Directory ${chalk.cyan(name)} already exists. Overwrite?`,
120
+ initialValue: false
121
+ });
122
+ if (isCancel(overwrite) || !overwrite) {
123
+ cancel("Operation cancelled.");
124
+ process.exit(0);
125
+ }
126
+ }
127
+ }
128
+ let packageManager = options.packageManager ?? detectPackageManager();
129
+ if (!options.packageManager && !options.yes) {
130
+ const pmChoice = await select({
131
+ message: "Package manager:",
132
+ options: PACKAGE_MANAGERS.map((pm) => ({
133
+ value: pm,
134
+ label: pm
135
+ })),
136
+ initialValue: packageManager
137
+ });
138
+ if (isCancel(pmChoice)) {
139
+ cancel("Operation cancelled.");
140
+ process.exit(0);
141
+ }
142
+ packageManager = pmChoice;
143
+ }
144
+ let tailwind = options.tailwind ?? true;
145
+ if (options.tailwind === void 0 && !options.yes) {
146
+ const twChoice = await confirm({
147
+ message: "Include Tailwind CSS?",
148
+ initialValue: true
149
+ });
150
+ if (isCancel(twChoice)) {
151
+ cancel("Operation cancelled.");
152
+ process.exit(0);
153
+ }
154
+ tailwind = twChoice;
155
+ }
156
+ let selectedIntegrationIds = [];
157
+ if (options.integrations) selectedIntegrationIds = options.integrations.split(",").map((s$1) => s$1.trim());
158
+ else if (!options.yes) {
159
+ const grouped = groupIntegrationsByCategory(manifest.integrations.filter((a) => a.type === "integration" && a.modes.includes("file-router")));
160
+ const categoryOptions = CATEGORY_ORDER.filter((cat) => grouped[cat]?.length).map((cat) => ({
161
+ value: cat,
162
+ label: CATEGORY_LABELS[cat] ?? cat,
163
+ hint: `${grouped[cat].length} integrations`
164
+ }));
165
+ note("Use arrow keys to navigate, space to select/deselect, enter to confirm.", "Integration Selection");
166
+ const selectedCategories = await multiselect({
167
+ message: "Which categories would you like to explore?",
168
+ options: categoryOptions,
169
+ required: false
170
+ });
171
+ if (isCancel(selectedCategories)) {
172
+ cancel("Operation cancelled.");
173
+ process.exit(0);
174
+ }
175
+ for (const category of selectedCategories) {
176
+ const categoryIntegrations = grouped[category];
177
+ if (!categoryIntegrations?.length) continue;
178
+ const integrationChoices = await multiselect({
179
+ message: `Select ${CATEGORY_LABELS[category]} integrations:`,
180
+ options: categoryIntegrations.map((integration) => ({
181
+ value: integration.id,
182
+ label: integration.name,
183
+ hint: integration.description
184
+ })),
185
+ required: false
186
+ });
187
+ if (isCancel(integrationChoices)) {
188
+ cancel("Operation cancelled.");
189
+ process.exit(0);
190
+ }
191
+ selectedIntegrationIds.push(...integrationChoices);
192
+ }
193
+ }
194
+ const integrationMap = new Map(manifest.integrations.map((a) => [a.id, a]));
195
+ const resolvedIds = new Set(selectedIntegrationIds);
196
+ for (const id of selectedIntegrationIds) {
197
+ const integration = integrationMap.get(id);
198
+ if (integration?.dependsOn) for (const dep of integration.dependsOn) resolvedIds.add(dep);
199
+ }
200
+ if (resolvedIds.size > 0) note(Array.from(resolvedIds).map((id) => {
201
+ const integration = integrationMap.get(id);
202
+ return ` ${!selectedIntegrationIds.includes(id) && resolvedIds.has(id) ? chalk.dim("(auto)") : chalk.green("+")} ${integration?.name ?? id}`;
203
+ }).join("\n"), "Selected Integrations");
204
+ if (!options.yes) {
205
+ const proceed = await confirm({
206
+ message: "Create project?",
207
+ initialValue: true
208
+ });
209
+ if (isCancel(proceed) || !proceed) {
210
+ cancel("Operation cancelled.");
211
+ process.exit(0);
212
+ }
213
+ }
214
+ s.start("Preparing project...");
215
+ let customTemplate;
216
+ if (options.template) try {
217
+ customTemplate = await loadTemplate(options.template);
218
+ for (const integrationId of customTemplate.integrations) resolvedIds.add(integrationId);
219
+ tailwind = customTemplate.tailwind;
220
+ } catch (error$1) {
221
+ s.stop("Failed to load template");
222
+ log.error(error$1 instanceof Error ? error$1.message : "Could not load template from URL.");
223
+ process.exit(1);
224
+ }
225
+ let chosenIntegrations = [];
226
+ if (resolvedIds.size > 0) try {
227
+ chosenIntegrations = await fetchIntegrations(Array.from(resolvedIds), integrationsPath);
228
+ } catch (error$1) {
229
+ s.stop("Failed to fetch integration details");
230
+ log.error("Could not fetch integration definitions.");
231
+ process.exit(1);
232
+ }
233
+ const compileOptions = {
234
+ projectName: name,
235
+ framework: customTemplate?.framework ?? "react",
236
+ mode: customTemplate?.mode ?? "file-router",
237
+ typescript: customTemplate?.typescript ?? true,
238
+ tailwind,
239
+ packageManager,
240
+ chosenIntegrations,
241
+ integrationOptions: customTemplate?.integrationOptions ?? {},
242
+ customTemplate
243
+ };
244
+ const output = compile(compileOptions);
245
+ s.stop("Project prepared");
246
+ s.start("Writing files...");
247
+ mkdirSync(targetDir, { recursive: true });
248
+ for (const [filePath, content] of Object.entries(output.files)) {
249
+ const fullPath = resolve(targetDir, filePath);
250
+ mkdirSync(resolve(fullPath, ".."), { recursive: true });
251
+ writeFileSync(fullPath, content, "utf-8");
252
+ }
253
+ await writeConfigFile(targetDir, compileOptions);
254
+ s.stop("Files written");
255
+ if (options.git !== false) {
256
+ s.start("Initializing git repository...");
257
+ try {
258
+ const { execSync } = await import("node:child_process");
259
+ execSync("git init", {
260
+ cwd: targetDir,
261
+ stdio: "ignore"
262
+ });
263
+ s.stop("Git initialized");
264
+ } catch {
265
+ s.stop("Git initialization skipped");
266
+ }
267
+ }
268
+ if (options.install !== false) {
269
+ s.start(`Installing dependencies with ${packageManager}...`);
270
+ const startTime = Date.now();
271
+ const interval = setInterval(() => {
272
+ const elapsed = Math.floor((Date.now() - startTime) / 1e3);
273
+ s.message(`Installing dependencies with ${packageManager}... (${elapsed}s)`);
274
+ }, 1e3);
275
+ try {
276
+ const { execSync } = await import("node:child_process");
277
+ execSync(packageManager === "yarn" ? "yarn" : `${packageManager} install`, {
278
+ cwd: targetDir,
279
+ stdio: "ignore"
280
+ });
281
+ clearInterval(interval);
282
+ const total = Math.floor((Date.now() - startTime) / 1e3);
283
+ s.stop(`Dependencies installed (${total}s)`);
284
+ } catch {
285
+ clearInterval(interval);
286
+ s.stop("Dependency installation failed");
287
+ log.warning(`Run "${packageManager} install" manually to install dependencies.`);
288
+ }
289
+ }
290
+ const relativePath = resolve(process.cwd()) === targetDir ? "." : name;
291
+ outro(chalk.green("Project created successfully!"));
292
+ console.log();
293
+ console.log("Next steps:");
294
+ console.log();
295
+ if (relativePath !== ".") console.log(` ${chalk.cyan("cd")} ${relativePath}`);
296
+ if (options.install === false) console.log(` ${chalk.cyan(packageManager)} install`);
297
+ console.log(` ${chalk.cyan(packageManager)} ${packageManager === "npm" ? "run " : ""}dev`);
298
+ console.log();
299
+ if (output.envVars.length > 0) {
300
+ console.log(chalk.yellow("Environment variables needed:"));
301
+ console.log();
302
+ for (const envVar of output.envVars) console.log(` ${chalk.cyan(envVar.name)} - ${envVar.description}`);
303
+ console.log();
304
+ console.log(` Add these to your ${chalk.cyan(".env.local")} file.`);
305
+ console.log();
306
+ }
307
+ for (const warning of output.warnings) log.warning(warning);
308
+ }
309
+
310
+ //#endregion
311
+ //#region src/commands/mcp.ts
312
+ function createServer() {
313
+ const server = new McpServer({
314
+ name: "TanStack CLI",
315
+ version: "0.0.1"
316
+ });
317
+ server.tool("listTanStackIntegrations", "List available integrations for creating TanStack applications", {}, async () => {
318
+ try {
319
+ const integrations = (await fetchManifest()).integrations.filter((a) => a.modes.includes("file-router")).map((integration) => ({
320
+ id: integration.id,
321
+ name: integration.name,
322
+ description: integration.description,
323
+ category: integration.category,
324
+ dependsOn: integration.dependsOn,
325
+ conflicts: integration.conflicts,
326
+ hasOptions: integration.hasOptions
327
+ }));
328
+ return { content: [{
329
+ type: "text",
330
+ text: JSON.stringify(integrations, null, 2)
331
+ }] };
332
+ } catch (error) {
333
+ return { content: [{
334
+ type: "text",
335
+ text: `Error fetching integrations: ${error}`
336
+ }] };
337
+ }
338
+ });
339
+ server.tool("createTanStackApplication", "Create a new TanStack Start application", {
340
+ projectName: z.string().describe("The name of the project (will be the directory name)"),
341
+ targetDir: z.string().describe("Absolute path where the project should be created"),
342
+ integrations: z.array(z.string()).optional().describe("Array of integration IDs to include. Use listTanStackIntegrations to see available options."),
343
+ integrationOptions: z.record(z.record(z.unknown())).optional().describe("Configuration for integrations. Format: {\"integrationId\": {\"optionName\": \"value\"}}"),
344
+ tailwind: z.boolean().optional().describe("Include Tailwind CSS (default: true)"),
345
+ packageManager: z.enum([
346
+ "npm",
347
+ "pnpm",
348
+ "yarn",
349
+ "bun",
350
+ "deno"
351
+ ]).optional().describe("Package manager to use (default: pnpm)")
352
+ }, async ({ projectName, targetDir, integrations, integrationOptions, tailwind, packageManager }) => {
353
+ try {
354
+ const { mkdirSync: mkdirSync$1, writeFileSync: writeFileSync$1 } = await import("node:fs");
355
+ const { resolve: resolve$1 } = await import("node:path");
356
+ const { execSync } = await import("node:child_process");
357
+ let chosenIntegrations = [];
358
+ if (integrations?.length) chosenIntegrations = await fetchIntegrations(integrations);
359
+ const output = compile({
360
+ projectName,
361
+ framework: "react",
362
+ mode: "file-router",
363
+ typescript: true,
364
+ tailwind: tailwind ?? true,
365
+ packageManager: packageManager ?? "pnpm",
366
+ chosenIntegrations,
367
+ integrationOptions: integrationOptions ?? {}
368
+ });
369
+ mkdirSync$1(targetDir, { recursive: true });
370
+ for (const [filePath, content] of Object.entries(output.files)) {
371
+ const fullPath = resolve$1(targetDir, filePath);
372
+ mkdirSync$1(resolve$1(fullPath, ".."), { recursive: true });
373
+ writeFileSync$1(fullPath, content, "utf-8");
374
+ }
375
+ try {
376
+ execSync("git init", {
377
+ cwd: targetDir,
378
+ stdio: "ignore"
379
+ });
380
+ } catch {}
381
+ const envVarList = output.envVars.length > 0 ? `\n\nRequired environment variables:\n${output.envVars.map((e) => `- ${e.name}: ${e.description}`).join("\n")}` : "";
382
+ const warnings = output.warnings.length > 0 ? `\n\nWarnings:\n${output.warnings.map((w) => `- ${w}`).join("\n")}` : "";
383
+ return { content: [{
384
+ type: "text",
385
+ text: `Project "${projectName}" created successfully at ${targetDir}
386
+
387
+ Files created: ${Object.keys(output.files).length}
388
+ Integrations included: ${chosenIntegrations.map((a) => a.name).join(", ") || "none"}${envVarList}${warnings}
389
+
390
+ Next steps:
391
+ 1. cd ${targetDir}
392
+ 2. ${packageManager ?? "pnpm"} install
393
+ 3. ${packageManager ?? "pnpm"} dev`
394
+ }] };
395
+ } catch (error) {
396
+ return { content: [{
397
+ type: "text",
398
+ text: `Error creating application: ${error}`
399
+ }] };
400
+ }
401
+ });
402
+ return server;
403
+ }
404
+ async function runMcp(options) {
405
+ const server = createServer();
406
+ if (options.sse) {
407
+ const app = express();
408
+ let transport = null;
409
+ app.get("/sse", (_req, res) => {
410
+ transport = new SSEServerTransport("/messages", res);
411
+ server.connect(transport);
412
+ });
413
+ app.post("/messages", (req, res) => {
414
+ if (transport) transport.handlePostMessage(req, res);
415
+ });
416
+ const port = parseInt(options.port ?? "8080", 10);
417
+ app.listen(port, () => {
418
+ console.log(`MCP server running at http://localhost:${port}/sse`);
419
+ });
420
+ } else {
421
+ const transport = new StdioServerTransport();
422
+ await server.connect(transport);
423
+ }
424
+ }
425
+
426
+ //#endregion
427
+ //#region src/bin.ts
428
+ const program = new Command();
429
+ program.name("tanstack").description("TanStack CLI for scaffolding and tooling").version("0.0.1");
430
+ program.command("create").argument("[project-name]", "name of the project").option("--template <template>", "URL to a custom template JSON file").option("--package-manager <pm>", "package manager (npm, pnpm, yarn, bun)").option("--integrations <integrations>", "comma-separated list of integration IDs").option("--no-install", "skip installing dependencies").option("--no-git", "skip initializing git repository").option("--no-tailwind", "skip tailwind CSS").option("-y, --yes", "skip prompts and use defaults").option("--target-dir <path>", "target directory for the project").option("--integrations-path <path>", "local path to integrations directory (for development)").description("Create a new TanStack Start project").action(runCreate);
431
+ program.command("mcp").option("--sse", "run in SSE mode (for HTTP transport)").option("--port <port>", "port for SSE server", "8080").description("Start the MCP server for AI agents").action(runMcp);
432
+ const integrationCommand = program.command("integration");
433
+ integrationCommand.command("init").option("--integrations-path <path>", "local path to integrations directory (for development)").description("Initialize an integration from the current project").action(async (options) => {
434
+ try {
435
+ await initIntegration(resolve(process.cwd()), options.integrationsPath);
436
+ } catch (error) {
437
+ console.error(error instanceof Error ? error.message : "An error occurred");
438
+ process.exit(1);
439
+ }
440
+ });
441
+ integrationCommand.command("compile").option("--integrations-path <path>", "local path to integrations directory (for development)").description("Compile/update the integration from the current project").action(async (options) => {
442
+ try {
443
+ await compileIntegration(resolve(process.cwd()), options.integrationsPath);
444
+ } catch (error) {
445
+ console.error(error instanceof Error ? error.message : "An error occurred");
446
+ process.exit(1);
447
+ }
448
+ });
449
+ const templateCommand = program.command("template");
450
+ templateCommand.command("init").description("Initialize a custom template from the current project").action(async () => {
451
+ try {
452
+ await initTemplate(resolve(process.cwd()));
453
+ } catch (error) {
454
+ console.error(error instanceof Error ? error.message : "An error occurred");
455
+ process.exit(1);
456
+ }
457
+ });
458
+ templateCommand.command("compile").description("Compile/update the custom template from the current project").action(async () => {
459
+ try {
460
+ await compileTemplate(resolve(process.cwd()));
461
+ } catch (error) {
462
+ console.error(error instanceof Error ? error.message : "An error occurred");
463
+ process.exit(1);
464
+ }
465
+ });
466
+ program.parse();
467
+
468
+ //#endregion
469
+ export { };
package/dist/index.cjs ADDED
@@ -0,0 +1,36 @@
1
+ const require_template = require('./template-BYKvtZrT.cjs');
2
+
3
+ exports.CONFIG_FILE = require_template.CONFIG_FILE;
4
+ exports.CategorySchema = require_template.CategorySchema;
5
+ exports.CommandSchema = require_template.CommandSchema;
6
+ exports.CustomTemplateCompiledSchema = require_template.CustomTemplateCompiledSchema;
7
+ exports.CustomTemplateInfoSchema = require_template.CustomTemplateInfoSchema;
8
+ exports.EnvVarSchema = require_template.EnvVarSchema;
9
+ exports.HookSchema = require_template.HookSchema;
10
+ exports.IntegrationCompiledSchema = require_template.IntegrationCompiledSchema;
11
+ exports.IntegrationInfoSchema = require_template.IntegrationInfoSchema;
12
+ exports.IntegrationOptionSchema = require_template.IntegrationOptionSchema;
13
+ exports.IntegrationOptionsSchema = require_template.IntegrationOptionsSchema;
14
+ exports.IntegrationPhaseSchema = require_template.IntegrationPhaseSchema;
15
+ exports.IntegrationTypeSchema = require_template.IntegrationTypeSchema;
16
+ exports.ManifestIntegrationSchema = require_template.ManifestIntegrationSchema;
17
+ exports.ManifestSchema = require_template.ManifestSchema;
18
+ exports.RouteSchema = require_template.RouteSchema;
19
+ exports.RouterModeSchema = require_template.RouterModeSchema;
20
+ exports.compile = require_template.compile;
21
+ exports.compileIntegration = require_template.compileIntegration;
22
+ exports.compileTemplate = require_template.compileTemplate;
23
+ exports.compileWithAttribution = require_template.compileWithAttribution;
24
+ exports.fetchIntegration = require_template.fetchIntegration;
25
+ exports.fetchIntegrationFiles = require_template.fetchIntegrationFiles;
26
+ exports.fetchIntegrationInfo = require_template.fetchIntegrationInfo;
27
+ exports.fetchIntegrations = require_template.fetchIntegrations;
28
+ exports.fetchManifest = require_template.fetchManifest;
29
+ exports.initIntegration = require_template.initIntegration;
30
+ exports.initTemplate = require_template.initTemplate;
31
+ exports.loadRemoteIntegration = require_template.loadRemoteIntegration;
32
+ exports.loadTemplate = require_template.loadTemplate;
33
+ exports.processTemplateFile = require_template.processTemplateFile;
34
+ exports.readConfigFile = require_template.readConfigFile;
35
+ exports.relativePath = require_template.relativePath;
36
+ exports.writeConfigFile = require_template.writeConfigFile;