@tanstack/cta-engine 0.10.0-alpha.10 → 0.10.0-alpha.11

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/add-ons.js CHANGED
@@ -91,10 +91,9 @@ export async function finalizeAddOns(framework, template, chosenAddOnIDs) {
91
91
  const finalAddOns = [...finalAddOnIDs].map((id) => addOns.find((a) => a.id === id));
92
92
  return finalAddOns;
93
93
  }
94
- export async function listAddOns(options) {
95
- const mode = options.template === 'file-router' ? 'file-router' : 'code-router';
96
- const addOns = await getAllAddOns(options.framework || DEFAULT_FRAMEWORK, mode);
97
- for (const addOn of addOns) {
94
+ export async function listAddOns(options, { forcedMode, forcedAddOns = [], }) {
95
+ const addOns = await getAllAddOns(options.framework || DEFAULT_FRAMEWORK, forcedMode || options.template || 'typescript');
96
+ for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
98
97
  console.log(`${chalk.bold(addOn.id)}: ${addOn.description}`);
99
98
  }
100
99
  }
package/dist/cli.js CHANGED
@@ -9,11 +9,9 @@ import { listAddOns } from './add-ons.js';
9
9
  import { DEFAULT_FRAMEWORK, SUPPORTED_FRAMEWORKS } from './constants.js';
10
10
  // import { initAddOn } from './custom-add-on.js'
11
11
  import { createDefaultEnvironment } from './environment.js';
12
- export function cli({ name, forcedMode, forcedAddOns, }) {
12
+ export function cli({ name, appName, forcedMode, forcedAddOns, }) {
13
13
  const program = new Command();
14
- program
15
- .name('create-tsrouter-app')
16
- .description('CLI to create a new TanStack application');
14
+ program.name(name).description(`CLI to create a new ${appName} application`);
17
15
  // program
18
16
  // .command('add')
19
17
  // .argument('add-on', 'Name of the add-on (or add-ons separated by commas)')
@@ -78,10 +76,17 @@ export function cli({ name, forcedMode, forcedAddOns, }) {
78
76
  }
79
77
  program.action(async (projectName, options) => {
80
78
  if (options.listAddOns) {
81
- await listAddOns(options);
79
+ await listAddOns(options, {
80
+ forcedMode,
81
+ forcedAddOns,
82
+ });
82
83
  }
83
84
  else if (options.mcp || options.mcpSse) {
84
- await runServer(!!options.mcpSse);
85
+ await runServer(!!options.mcpSse, {
86
+ forcedMode,
87
+ forcedAddOns,
88
+ appName,
89
+ });
85
90
  }
86
91
  else {
87
92
  try {
@@ -94,10 +99,10 @@ export function cli({ name, forcedMode, forcedAddOns, }) {
94
99
  }
95
100
  let finalOptions = await normalizeOptions(cliOptions, forcedAddOns);
96
101
  if (finalOptions) {
97
- intro(`Creating a new TanStack app in ${projectName}...`);
102
+ intro(`Creating a new ${appName} app in ${projectName}...`);
98
103
  }
99
104
  else {
100
- intro("Let's configure your TanStack application");
105
+ intro(`Let's configure your ${appName} application`);
101
106
  finalOptions = await promptForOptions(cliOptions, {
102
107
  forcedMode,
103
108
  forcedAddOns,
@@ -107,6 +112,7 @@ export function cli({ name, forcedMode, forcedAddOns, }) {
107
112
  environment: createDefaultEnvironment(),
108
113
  cwd: options.targetDir || undefined,
109
114
  name,
115
+ appName,
110
116
  });
111
117
  }
112
118
  catch (error) {
@@ -209,7 +209,7 @@ async function copyAddOnFile(environment, content, target, targetPath, templateF
209
209
  }
210
210
  }
211
211
  }
212
- export async function createApp(options, { silent = false, environment, cwd, name = 'create-tsrouter-app', }) {
212
+ export async function createApp(options, { silent = false, environment, cwd, appName = 'TanStack', }) {
213
213
  environment.startRun();
214
214
  const templateDirBase = resolve(getTemplatesRoot(), options.framework, 'base');
215
215
  const templateDirRouter = resolve(getTemplatesRoot(), options.framework, options.mode);
@@ -480,7 +480,7 @@ ${environment.getErrors().join('\n')}`;
480
480
  if (options.packageManager === 'deno') {
481
481
  startCommand = `deno ${isAddOnEnabled('start') ? 'task dev' : 'start'}`;
482
482
  }
483
- outro(`Your TanStack app is ready in '${basename(targetDir)}'.
483
+ outro(`Your ${appName} app is ready in '${basename(targetDir)}'.
484
484
 
485
485
  Use the following commands to start your app:
486
486
  % cd ${options.projectName}
package/dist/mcp.js CHANGED
@@ -6,10 +6,6 @@ import { z } from 'zod';
6
6
  import { createApp } from './create-app.js';
7
7
  import { finalizeAddOns } from './add-ons.js';
8
8
  import { createDefaultEnvironment } from './environment.js';
9
- const server = new McpServer({
10
- name: 'Demo',
11
- version: '1.0.0',
12
- });
13
9
  const tanStackReactAddOns = [
14
10
  {
15
11
  id: 'clerk',
@@ -52,63 +48,6 @@ const tanStackReactAddOns = [
52
48
  description: 'Add an AI chatbot example to the application',
53
49
  },
54
50
  ];
55
- server.tool('listTanStackReactAddOns', {}, () => {
56
- return {
57
- content: [{ type: 'text', text: JSON.stringify(tanStackReactAddOns) }],
58
- };
59
- });
60
- server.tool('createTanStackReactApplication', {
61
- projectName: z
62
- .string()
63
- .describe('The package.json module name of the application (will also be the directory name)'),
64
- cwd: z.string().describe('The directory to create the application in'),
65
- addOns: z
66
- .array(z.enum([
67
- 'clerk',
68
- 'convex',
69
- 'form',
70
- 'netlify',
71
- 'sentry',
72
- 'shadcn',
73
- 'start',
74
- 'store',
75
- 'tanstack-query',
76
- 'tanchat',
77
- ]))
78
- .describe('The IDs of the add-ons to install'),
79
- }, async ({ projectName, addOns, cwd }) => {
80
- try {
81
- process.chdir(cwd);
82
- const chosenAddOns = await finalizeAddOns('react', 'file-router', addOns);
83
- await createApp({
84
- projectName: projectName.replace(/^\//, './'),
85
- framework: 'react',
86
- typescript: true,
87
- tailwind: true,
88
- packageManager: 'pnpm',
89
- toolchain: 'none',
90
- mode: 'file-router',
91
- addOns: true,
92
- chosenAddOns,
93
- git: true,
94
- variableValues: {},
95
- }, {
96
- silent: true,
97
- environment: createDefaultEnvironment(),
98
- name: 'create-tsrouter-app',
99
- });
100
- return {
101
- content: [{ type: 'text', text: 'Application created successfully' }],
102
- };
103
- }
104
- catch (error) {
105
- return {
106
- content: [
107
- { type: 'text', text: `Error creating application: ${error}` },
108
- ],
109
- };
110
- }
111
- });
112
51
  const tanStackSolidAddOns = [
113
52
  {
114
53
  id: 'solid-ui',
@@ -126,6 +65,10 @@ const tanStackSolidAddOns = [
126
65
  id: 'store',
127
66
  description: 'Enable the TanStack Store state management library',
128
67
  },
68
+ {
69
+ id: 'start',
70
+ description: 'Set this if you want a TanStack Start application that supports server functions or APIs',
71
+ },
129
72
  {
130
73
  id: 'tanstack-query',
131
74
  description: 'Enable TanStack Query for data fetching',
@@ -135,63 +78,136 @@ const tanStackSolidAddOns = [
135
78
  description: 'Add an AI chatbot example to the application',
136
79
  },
137
80
  ];
138
- server.tool('listTanStackSolidAddOns', {}, () => {
139
- return {
140
- content: [{ type: 'text', text: JSON.stringify(tanStackSolidAddOns) }],
141
- };
142
- });
143
- server.tool('createTanStackSolidApplication', {
144
- projectName: z
145
- .string()
146
- .describe('The package.json module name of the application (will also be the directory name)'),
147
- cwd: z.string().describe('The directory to create the application in'),
148
- addOns: z
149
- .array(z.enum([
150
- 'solid-ui',
151
- 'form',
152
- 'sentry',
153
- 'store',
154
- 'tanstack-query',
155
- 'tanchat',
156
- ]))
157
- .describe('The IDs of the add-ons to install'),
158
- }, async ({ projectName, addOns, cwd }) => {
159
- try {
160
- process.chdir(cwd);
161
- const chosenAddOns = await finalizeAddOns('solid', 'file-router', addOns);
162
- await createApp({
163
- projectName: projectName.replace(/^\//, './'),
164
- framework: 'solid',
165
- typescript: true,
166
- tailwind: true,
167
- packageManager: 'pnpm',
168
- toolchain: 'none',
169
- mode: 'file-router',
170
- addOns: true,
171
- chosenAddOns,
172
- git: true,
173
- variableValues: {},
174
- }, {
175
- silent: true,
176
- environment: createDefaultEnvironment(),
177
- name: 'create-tsrouter-app',
178
- });
81
+ function createServer({ appName, forcedAddOns = [], name, }) {
82
+ const server = new McpServer({
83
+ name: `${appName} Application Builder`,
84
+ version: '1.0.0',
85
+ });
86
+ server.tool('listTanStackReactAddOns', {}, () => {
179
87
  return {
180
- content: [{ type: 'text', text: 'Application created successfully' }],
88
+ content: [{ type: 'text', text: JSON.stringify(tanStackReactAddOns) }],
181
89
  };
182
- }
183
- catch (error) {
90
+ });
91
+ server.tool('createTanStackReactApplication', {
92
+ projectName: z
93
+ .string()
94
+ .describe('The package.json module name of the application (will also be the directory name)'),
95
+ cwd: z.string().describe('The directory to create the application in'),
96
+ addOns: z
97
+ .array(z.enum([
98
+ 'clerk',
99
+ 'convex',
100
+ 'form',
101
+ 'netlify',
102
+ 'sentry',
103
+ 'shadcn',
104
+ 'start',
105
+ 'store',
106
+ 'tanstack-query',
107
+ 'tanchat',
108
+ ]))
109
+ .describe('The IDs of the add-ons to install'),
110
+ targetDir: z
111
+ .string()
112
+ .describe('The directory to create the application in. Use the absolute path of the directory you want the application to be created in'),
113
+ }, async ({ projectName, addOns, cwd, targetDir }) => {
114
+ try {
115
+ process.chdir(cwd);
116
+ const chosenAddOns = await finalizeAddOns('react', 'file-router', Array.from(new Set([...addOns, ...forcedAddOns])));
117
+ await createApp({
118
+ projectName: projectName.replace(/^\//, './'),
119
+ framework: 'react',
120
+ typescript: true,
121
+ tailwind: true,
122
+ packageManager: 'pnpm',
123
+ toolchain: 'none',
124
+ mode: 'file-router',
125
+ addOns: true,
126
+ chosenAddOns,
127
+ git: true,
128
+ variableValues: {},
129
+ }, {
130
+ silent: true,
131
+ environment: createDefaultEnvironment(),
132
+ name,
133
+ cwd: targetDir,
134
+ });
135
+ return {
136
+ content: [{ type: 'text', text: 'Application created successfully' }],
137
+ };
138
+ }
139
+ catch (error) {
140
+ return {
141
+ content: [
142
+ { type: 'text', text: `Error creating application: ${error}` },
143
+ ],
144
+ };
145
+ }
146
+ });
147
+ server.tool('listTanStackSolidAddOns', {}, () => {
184
148
  return {
185
- content: [
186
- { type: 'text', text: `Error creating application: ${error}` },
187
- ],
149
+ content: [{ type: 'text', text: JSON.stringify(tanStackSolidAddOns) }],
188
150
  };
189
- }
190
- });
191
- export default async function runServer(sse) {
151
+ });
152
+ server.tool('createTanStackSolidApplication', {
153
+ projectName: z
154
+ .string()
155
+ .describe('The package.json module name of the application (will also be the directory name)'),
156
+ cwd: z.string().describe('The directory to create the application in'),
157
+ addOns: z
158
+ .array(z.enum([
159
+ 'solid-ui',
160
+ 'form',
161
+ 'sentry',
162
+ 'store',
163
+ 'tanstack-query',
164
+ 'tanchat',
165
+ ]))
166
+ .describe('The IDs of the add-ons to install'),
167
+ targetDir: z
168
+ .string()
169
+ .describe('The directory to create the application in. Use the absolute path of the directory you want the application to be created in'),
170
+ }, async ({ projectName, addOns, cwd, targetDir }) => {
171
+ try {
172
+ process.chdir(cwd);
173
+ const chosenAddOns = await finalizeAddOns('solid', 'file-router', Array.from(new Set([...addOns, ...forcedAddOns])));
174
+ await createApp({
175
+ projectName: projectName.replace(/^\//, './'),
176
+ framework: 'solid',
177
+ typescript: true,
178
+ tailwind: true,
179
+ packageManager: 'pnpm',
180
+ toolchain: 'none',
181
+ mode: 'file-router',
182
+ addOns: true,
183
+ chosenAddOns,
184
+ git: true,
185
+ variableValues: {},
186
+ }, {
187
+ silent: true,
188
+ environment: createDefaultEnvironment(),
189
+ name,
190
+ cwd: targetDir,
191
+ });
192
+ return {
193
+ content: [{ type: 'text', text: 'Application created successfully' }],
194
+ };
195
+ }
196
+ catch (error) {
197
+ return {
198
+ content: [
199
+ { type: 'text', text: `Error creating application: ${error}` },
200
+ ],
201
+ };
202
+ }
203
+ });
204
+ return server;
205
+ }
206
+ export default async function runServer(sse, { forcedAddOns, appName, name, }) {
207
+ let transport = null;
208
+ const server = createServer({ appName, forcedAddOns, name });
192
209
  if (sse) {
193
210
  const app = express();
194
- let transport = null;
195
211
  app.get('/sse', (req, res) => {
196
212
  transport = new SSEServerTransport('/messages', res);
197
213
  server.connect(transport);
@@ -1,5 +1,8 @@
1
- import type { AddOn, CliOptions, Framework } from './types.js';
1
+ import type { AddOn, CliOptions, Framework, TemplateOptions } from './types.js';
2
2
  export declare function getAllAddOns(framework: Framework, template: string): Promise<Array<AddOn>>;
3
3
  export declare function finalizeAddOns(framework: Framework, template: string, chosenAddOnIDs: Array<string>): Promise<Array<AddOn>>;
4
- export declare function listAddOns(options: CliOptions): Promise<void>;
4
+ export declare function listAddOns(options: CliOptions, { forcedMode, forcedAddOns, }: {
5
+ forcedMode?: TemplateOptions;
6
+ forcedAddOns?: Array<string>;
7
+ }): Promise<void>;
5
8
  export declare function loadRemoteAddOn(url: string): Promise<AddOn>;
@@ -1,5 +1,6 @@
1
- export declare function cli({ name, forcedMode, forcedAddOns, }: {
1
+ export declare function cli({ name, appName, forcedMode, forcedAddOns, }: {
2
2
  name: string;
3
+ appName: string;
3
4
  forcedMode?: 'typescript' | 'javascript' | 'file-router';
4
5
  forcedAddOns?: Array<string>;
5
6
  }): void;
@@ -1,7 +1,8 @@
1
1
  import type { Environment, Options } from './types.js';
2
- export declare function createApp(options: Options, { silent, environment, cwd, name, }: {
2
+ export declare function createApp(options: Options, { silent, environment, cwd, appName, }: {
3
3
  silent?: boolean;
4
4
  environment: Environment;
5
5
  cwd?: string;
6
- name: string;
6
+ name?: string;
7
+ appName?: string;
7
8
  }): Promise<void>;
@@ -1 +1,7 @@
1
- export default function runServer(sse: boolean): Promise<void>;
1
+ import type { TemplateOptions } from './types.js';
2
+ export default function runServer(sse: boolean, { forcedAddOns, appName, name, }: {
3
+ forcedMode?: TemplateOptions;
4
+ forcedAddOns?: Array<string>;
5
+ appName?: string;
6
+ name?: string;
7
+ }): Promise<void>;
@@ -2,6 +2,7 @@ import type { CODE_ROUTER, FILE_ROUTER } from './constants.js';
2
2
  import type { PackageManager } from './package-manager.js';
3
3
  import type { ToolChain } from './toolchain.js';
4
4
  export type Framework = 'solid' | 'react';
5
+ export type TemplateOptions = 'typescript' | 'javascript' | 'file-router';
5
6
  export interface Options {
6
7
  framework: Framework;
7
8
  projectName: string;
@@ -17,7 +18,7 @@ export interface Options {
17
18
  overlay?: AddOn | undefined;
18
19
  }
19
20
  export interface CliOptions {
20
- template?: 'typescript' | 'javascript' | 'file-router';
21
+ template?: TemplateOptions;
21
22
  framework?: Framework;
22
23
  tailwind?: boolean;
23
24
  packageManager?: PackageManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cta-engine",
3
- "version": "0.10.0-alpha.10",
3
+ "version": "0.10.0-alpha.11",
4
4
  "description": "Tanstack Application Builder Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/add-ons.ts CHANGED
@@ -2,10 +2,11 @@ import { readFile } from 'node:fs/promises'
2
2
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
3
3
  import { resolve } from 'node:path'
4
4
  import chalk from 'chalk'
5
- import { getTemplatesRoot } from './templates.js'
6
5
 
6
+ import { getTemplatesRoot } from './templates.js'
7
7
  import { DEFAULT_FRAMEWORK } from './constants.js'
8
- import type { AddOn, CliOptions, Framework } from './types.js'
8
+
9
+ import type { AddOn, CliOptions, Framework, TemplateOptions } from './types.js'
9
10
 
10
11
  function isDirectory(path: string): boolean {
11
12
  return statSync(path).isDirectory()
@@ -121,14 +122,21 @@ export async function finalizeAddOns(
121
122
  return finalAddOns
122
123
  }
123
124
 
124
- export async function listAddOns(options: CliOptions) {
125
- const mode =
126
- options.template === 'file-router' ? 'file-router' : 'code-router'
125
+ export async function listAddOns(
126
+ options: CliOptions,
127
+ {
128
+ forcedMode,
129
+ forcedAddOns = [],
130
+ }: {
131
+ forcedMode?: TemplateOptions
132
+ forcedAddOns?: Array<string>
133
+ },
134
+ ) {
127
135
  const addOns = await getAllAddOns(
128
136
  options.framework || DEFAULT_FRAMEWORK,
129
- mode,
137
+ forcedMode || options.template || 'typescript',
130
138
  )
131
- for (const addOn of addOns) {
139
+ for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
132
140
  console.log(`${chalk.bold(addOn.id)}: ${addOn.description}`)
133
141
  }
134
142
  }
package/src/cli.ts CHANGED
@@ -20,18 +20,18 @@ import type { CliOptions, Framework } from './types.js'
20
20
 
21
21
  export function cli({
22
22
  name,
23
+ appName,
23
24
  forcedMode,
24
25
  forcedAddOns,
25
26
  }: {
26
27
  name: string
28
+ appName: string
27
29
  forcedMode?: 'typescript' | 'javascript' | 'file-router'
28
30
  forcedAddOns?: Array<string>
29
31
  }) {
30
32
  const program = new Command()
31
33
 
32
- program
33
- .name('create-tsrouter-app')
34
- .description('CLI to create a new TanStack application')
34
+ program.name(name).description(`CLI to create a new ${appName} application`)
35
35
 
36
36
  // program
37
37
  // .command('add')
@@ -139,9 +139,16 @@ export function cli({
139
139
 
140
140
  program.action(async (projectName: string, options: CliOptions) => {
141
141
  if (options.listAddOns) {
142
- await listAddOns(options)
142
+ await listAddOns(options, {
143
+ forcedMode,
144
+ forcedAddOns,
145
+ })
143
146
  } else if (options.mcp || options.mcpSse) {
144
- await runServer(!!options.mcpSse)
147
+ await runServer(!!options.mcpSse, {
148
+ forcedMode,
149
+ forcedAddOns,
150
+ appName,
151
+ })
145
152
  } else {
146
153
  try {
147
154
  const cliOptions = {
@@ -155,9 +162,9 @@ export function cli({
155
162
 
156
163
  let finalOptions = await normalizeOptions(cliOptions, forcedAddOns)
157
164
  if (finalOptions) {
158
- intro(`Creating a new TanStack app in ${projectName}...`)
165
+ intro(`Creating a new ${appName} app in ${projectName}...`)
159
166
  } else {
160
- intro("Let's configure your TanStack application")
167
+ intro(`Let's configure your ${appName} application`)
161
168
  finalOptions = await promptForOptions(cliOptions, {
162
169
  forcedMode,
163
170
  forcedAddOns,
@@ -167,6 +174,7 @@ export function cli({
167
174
  environment: createDefaultEnvironment(),
168
175
  cwd: options.targetDir || undefined,
169
176
  name,
177
+ appName,
170
178
  })
171
179
  } catch (error) {
172
180
  log.error(
package/src/create-app.ts CHANGED
@@ -304,12 +304,13 @@ export async function createApp(
304
304
  silent = false,
305
305
  environment,
306
306
  cwd,
307
- name = 'create-tsrouter-app',
307
+ appName = 'TanStack',
308
308
  }: {
309
309
  silent?: boolean
310
310
  environment: Environment
311
311
  cwd?: string
312
- name: string
312
+ name?: string
313
+ appName?: string
313
314
  },
314
315
  ) {
315
316
  environment.startRun()
@@ -782,7 +783,7 @@ ${environment.getErrors().join('\n')}`
782
783
  startCommand = `deno ${isAddOnEnabled('start') ? 'task dev' : 'start'}`
783
784
  }
784
785
 
785
- outro(`Your TanStack app is ready in '${basename(targetDir)}'.
786
+ outro(`Your ${appName} app is ready in '${basename(targetDir)}'.
786
787
 
787
788
  Use the following commands to start your app:
788
789
  % cd ${options.projectName}
package/src/mcp.ts CHANGED
@@ -8,10 +8,7 @@ import { createApp } from './create-app.js'
8
8
  import { finalizeAddOns } from './add-ons.js'
9
9
  import { createDefaultEnvironment } from './environment.js'
10
10
 
11
- const server = new McpServer({
12
- name: 'Demo',
13
- version: '1.0.0',
14
- })
11
+ import type { TemplateOptions } from './types.js'
15
12
 
16
13
  const tanStackReactAddOns = [
17
14
  {
@@ -57,79 +54,6 @@ const tanStackReactAddOns = [
57
54
  },
58
55
  ]
59
56
 
60
- server.tool('listTanStackReactAddOns', {}, () => {
61
- return {
62
- content: [{ type: 'text', text: JSON.stringify(tanStackReactAddOns) }],
63
- }
64
- })
65
-
66
- server.tool(
67
- 'createTanStackReactApplication',
68
- {
69
- projectName: z
70
- .string()
71
- .describe(
72
- 'The package.json module name of the application (will also be the directory name)',
73
- ),
74
- cwd: z.string().describe('The directory to create the application in'),
75
- addOns: z
76
- .array(
77
- z.enum([
78
- 'clerk',
79
- 'convex',
80
- 'form',
81
- 'netlify',
82
- 'sentry',
83
- 'shadcn',
84
- 'start',
85
- 'store',
86
- 'tanstack-query',
87
- 'tanchat',
88
- ]),
89
- )
90
- .describe('The IDs of the add-ons to install'),
91
- },
92
- async ({ projectName, addOns, cwd }) => {
93
- try {
94
- process.chdir(cwd)
95
- const chosenAddOns = await finalizeAddOns(
96
- 'react',
97
- 'file-router',
98
- addOns as unknown as Array<string>,
99
- )
100
- await createApp(
101
- {
102
- projectName: projectName.replace(/^\//, './'),
103
- framework: 'react',
104
- typescript: true,
105
- tailwind: true,
106
- packageManager: 'pnpm',
107
- toolchain: 'none',
108
- mode: 'file-router',
109
- addOns: true,
110
- chosenAddOns,
111
- git: true,
112
- variableValues: {},
113
- },
114
- {
115
- silent: true,
116
- environment: createDefaultEnvironment(),
117
- name: 'create-tsrouter-app',
118
- },
119
- )
120
- return {
121
- content: [{ type: 'text', text: 'Application created successfully' }],
122
- }
123
- } catch (error) {
124
- return {
125
- content: [
126
- { type: 'text', text: `Error creating application: ${error}` },
127
- ],
128
- }
129
- }
130
- },
131
- )
132
-
133
57
  const tanStackSolidAddOns = [
134
58
  {
135
59
  id: 'solid-ui',
@@ -147,6 +71,11 @@ const tanStackSolidAddOns = [
147
71
  id: 'store',
148
72
  description: 'Enable the TanStack Store state management library',
149
73
  },
74
+ {
75
+ id: 'start',
76
+ description:
77
+ 'Set this if you want a TanStack Start application that supports server functions or APIs',
78
+ },
150
79
  {
151
80
  id: 'tanstack-query',
152
81
  description: 'Enable TanStack Query for data fetching',
@@ -157,81 +86,200 @@ const tanStackSolidAddOns = [
157
86
  },
158
87
  ]
159
88
 
160
- server.tool('listTanStackSolidAddOns', {}, () => {
161
- return {
162
- content: [{ type: 'text', text: JSON.stringify(tanStackSolidAddOns) }],
163
- }
164
- })
89
+ function createServer({
90
+ appName,
91
+ forcedAddOns = [],
92
+ name,
93
+ }: {
94
+ appName?: string
95
+ forcedAddOns?: Array<string>
96
+ name?: string
97
+ }) {
98
+ const server = new McpServer({
99
+ name: `${appName} Application Builder`,
100
+ version: '1.0.0',
101
+ })
165
102
 
166
- server.tool(
167
- 'createTanStackSolidApplication',
168
- {
169
- projectName: z
170
- .string()
171
- .describe(
172
- 'The package.json module name of the application (will also be the directory name)',
173
- ),
174
- cwd: z.string().describe('The directory to create the application in'),
175
- addOns: z
176
- .array(
177
- z.enum([
178
- 'solid-ui',
179
- 'form',
180
- 'sentry',
181
- 'store',
182
- 'tanstack-query',
183
- 'tanchat',
184
- ]),
185
- )
186
- .describe('The IDs of the add-ons to install'),
187
- },
188
- async ({ projectName, addOns, cwd }) => {
189
- try {
190
- process.chdir(cwd)
191
- const chosenAddOns = await finalizeAddOns(
192
- 'solid',
193
- 'file-router',
194
- addOns as unknown as Array<string>,
195
- )
196
- await createApp(
197
- {
198
- projectName: projectName.replace(/^\//, './'),
199
- framework: 'solid',
200
- typescript: true,
201
- tailwind: true,
202
- packageManager: 'pnpm',
203
- toolchain: 'none',
204
- mode: 'file-router',
205
- addOns: true,
206
- chosenAddOns,
207
- git: true,
208
- variableValues: {},
209
- },
210
- {
211
- silent: true,
212
- environment: createDefaultEnvironment(),
213
- name: 'create-tsrouter-app',
214
- },
215
- )
216
- return {
217
- content: [{ type: 'text', text: 'Application created successfully' }],
218
- }
219
- } catch (error) {
220
- return {
221
- content: [
222
- { type: 'text', text: `Error creating application: ${error}` },
223
- ],
103
+ server.tool('listTanStackReactAddOns', {}, () => {
104
+ return {
105
+ content: [{ type: 'text', text: JSON.stringify(tanStackReactAddOns) }],
106
+ }
107
+ })
108
+
109
+ server.tool(
110
+ 'createTanStackReactApplication',
111
+ {
112
+ projectName: z
113
+ .string()
114
+ .describe(
115
+ 'The package.json module name of the application (will also be the directory name)',
116
+ ),
117
+ cwd: z.string().describe('The directory to create the application in'),
118
+ addOns: z
119
+ .array(
120
+ z.enum([
121
+ 'clerk',
122
+ 'convex',
123
+ 'form',
124
+ 'netlify',
125
+ 'sentry',
126
+ 'shadcn',
127
+ 'start',
128
+ 'store',
129
+ 'tanstack-query',
130
+ 'tanchat',
131
+ ]),
132
+ )
133
+ .describe('The IDs of the add-ons to install'),
134
+ targetDir: z
135
+ .string()
136
+ .describe(
137
+ 'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
138
+ ),
139
+ },
140
+ async ({ projectName, addOns, cwd, targetDir }) => {
141
+ try {
142
+ process.chdir(cwd)
143
+ const chosenAddOns = await finalizeAddOns(
144
+ 'react',
145
+ 'file-router',
146
+ Array.from(
147
+ new Set([...(addOns as unknown as Array<string>), ...forcedAddOns]),
148
+ ),
149
+ )
150
+ await createApp(
151
+ {
152
+ projectName: projectName.replace(/^\//, './'),
153
+ framework: 'react',
154
+ typescript: true,
155
+ tailwind: true,
156
+ packageManager: 'pnpm',
157
+ toolchain: 'none',
158
+ mode: 'file-router',
159
+ addOns: true,
160
+ chosenAddOns,
161
+ git: true,
162
+ variableValues: {},
163
+ },
164
+ {
165
+ silent: true,
166
+ environment: createDefaultEnvironment(),
167
+ name,
168
+ cwd: targetDir,
169
+ },
170
+ )
171
+ return {
172
+ content: [{ type: 'text', text: 'Application created successfully' }],
173
+ }
174
+ } catch (error) {
175
+ return {
176
+ content: [
177
+ { type: 'text', text: `Error creating application: ${error}` },
178
+ ],
179
+ }
224
180
  }
181
+ },
182
+ )
183
+
184
+ server.tool('listTanStackSolidAddOns', {}, () => {
185
+ return {
186
+ content: [{ type: 'text', text: JSON.stringify(tanStackSolidAddOns) }],
225
187
  }
188
+ })
189
+
190
+ server.tool(
191
+ 'createTanStackSolidApplication',
192
+ {
193
+ projectName: z
194
+ .string()
195
+ .describe(
196
+ 'The package.json module name of the application (will also be the directory name)',
197
+ ),
198
+ cwd: z.string().describe('The directory to create the application in'),
199
+ addOns: z
200
+ .array(
201
+ z.enum([
202
+ 'solid-ui',
203
+ 'form',
204
+ 'sentry',
205
+ 'store',
206
+ 'tanstack-query',
207
+ 'tanchat',
208
+ ]),
209
+ )
210
+ .describe('The IDs of the add-ons to install'),
211
+ targetDir: z
212
+ .string()
213
+ .describe(
214
+ 'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
215
+ ),
216
+ },
217
+ async ({ projectName, addOns, cwd, targetDir }) => {
218
+ try {
219
+ process.chdir(cwd)
220
+ const chosenAddOns = await finalizeAddOns(
221
+ 'solid',
222
+ 'file-router',
223
+ Array.from(
224
+ new Set([...(addOns as unknown as Array<string>), ...forcedAddOns]),
225
+ ),
226
+ )
227
+ await createApp(
228
+ {
229
+ projectName: projectName.replace(/^\//, './'),
230
+ framework: 'solid',
231
+ typescript: true,
232
+ tailwind: true,
233
+ packageManager: 'pnpm',
234
+ toolchain: 'none',
235
+ mode: 'file-router',
236
+ addOns: true,
237
+ chosenAddOns,
238
+ git: true,
239
+ variableValues: {},
240
+ },
241
+ {
242
+ silent: true,
243
+ environment: createDefaultEnvironment(),
244
+ name,
245
+ cwd: targetDir,
246
+ },
247
+ )
248
+ return {
249
+ content: [{ type: 'text', text: 'Application created successfully' }],
250
+ }
251
+ } catch (error) {
252
+ return {
253
+ content: [
254
+ { type: 'text', text: `Error creating application: ${error}` },
255
+ ],
256
+ }
257
+ }
258
+ },
259
+ )
260
+
261
+ return server
262
+ }
263
+
264
+ export default async function runServer(
265
+ sse: boolean,
266
+ {
267
+ forcedAddOns,
268
+ appName,
269
+ name,
270
+ }: {
271
+ forcedMode?: TemplateOptions
272
+ forcedAddOns?: Array<string>
273
+ appName?: string
274
+ name?: string
226
275
  },
227
- )
276
+ ) {
277
+ let transport: SSEServerTransport | null = null
228
278
 
229
- export default async function runServer(sse: boolean) {
279
+ const server = createServer({ appName, forcedAddOns, name })
230
280
  if (sse) {
231
281
  const app = express()
232
282
 
233
- let transport: SSEServerTransport | null = null
234
-
235
283
  app.get('/sse', (req, res) => {
236
284
  transport = new SSEServerTransport('/messages', res)
237
285
  server.connect(transport)
package/src/types.ts CHANGED
@@ -4,6 +4,8 @@ import type { ToolChain } from './toolchain.js'
4
4
 
5
5
  export type Framework = 'solid' | 'react'
6
6
 
7
+ export type TemplateOptions = 'typescript' | 'javascript' | 'file-router'
8
+
7
9
  export interface Options {
8
10
  framework: Framework
9
11
  projectName: string
@@ -20,7 +22,7 @@ export interface Options {
20
22
  }
21
23
 
22
24
  export interface CliOptions {
23
- template?: 'typescript' | 'javascript' | 'file-router'
25
+ template?: TemplateOptions
24
26
  framework?: Framework
25
27
  tailwind?: boolean
26
28
  packageManager?: PackageManager