@tanstack/cli 0.60.1 → 0.62.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.
Files changed (66) hide show
  1. package/dist/cli.js +266 -11
  2. package/dist/command-line.js +103 -8
  3. package/dist/discovery.js +144 -0
  4. package/dist/options.js +35 -2
  5. package/dist/types/command-line.d.ts +7 -0
  6. package/dist/types/{mcp/types.d.ts → discovery.d.ts} +23 -75
  7. package/dist/types/types.d.ts +1 -2
  8. package/dist/types/ui-prompts.d.ts +5 -0
  9. package/dist/ui-prompts.js +26 -0
  10. package/package.json +6 -5
  11. package/skills/CHANGELOG.md +18 -0
  12. package/skills/add-addons-existing-app/SKILL.md +113 -0
  13. package/skills/choose-ecosystem-integrations/SKILL.md +140 -0
  14. package/skills/choose-ecosystem-integrations/references/authentication-providers.md +19 -0
  15. package/skills/choose-ecosystem-integrations/references/data-layer-providers.md +20 -0
  16. package/skills/choose-ecosystem-integrations/references/deployment-targets.md +19 -0
  17. package/skills/create-app-scaffold/SKILL.md +132 -0
  18. package/skills/create-app-scaffold/references/create-flag-compatibility-matrix.md +34 -0
  19. package/skills/create-app-scaffold/references/deployment-providers.md +19 -0
  20. package/skills/create-app-scaffold/references/framework-adapters.md +17 -0
  21. package/skills/create-app-scaffold/references/toolchains.md +17 -0
  22. package/skills/maintain-custom-addons-dev-watch/SKILL.md +118 -0
  23. package/skills/query-docs-library-metadata/SKILL.md +85 -0
  24. package/skills/query-docs-library-metadata/references/discovery-command-output-schemas.md +70 -0
  25. package/CHANGELOG.md +0 -787
  26. package/dist/mcp/api.js +0 -31
  27. package/dist/mcp/tools.js +0 -250
  28. package/dist/mcp/types.js +0 -37
  29. package/dist/mcp.js +0 -181
  30. package/dist/types/mcp/api.d.ts +0 -4
  31. package/dist/types/mcp/tools.d.ts +0 -2
  32. package/dist/types/mcp.d.ts +0 -5
  33. package/playwright-report/index.html +0 -85
  34. package/playwright.config.ts +0 -21
  35. package/src/bin.ts +0 -15
  36. package/src/cli.ts +0 -767
  37. package/src/command-line.ts +0 -473
  38. package/src/dev-watch.ts +0 -564
  39. package/src/file-syncer.ts +0 -263
  40. package/src/index.ts +0 -21
  41. package/src/mcp/api.ts +0 -42
  42. package/src/mcp/tools.ts +0 -323
  43. package/src/mcp/types.ts +0 -46
  44. package/src/mcp.ts +0 -263
  45. package/src/options.ts +0 -234
  46. package/src/types.ts +0 -28
  47. package/src/ui-environment.ts +0 -74
  48. package/src/ui-prompts.ts +0 -355
  49. package/src/utils.ts +0 -30
  50. package/test-results/.last-run.json +0 -4
  51. package/tests/command-line.test.ts +0 -622
  52. package/tests/index.test.ts +0 -9
  53. package/tests/mcp.test.ts +0 -225
  54. package/tests/options.test.ts +0 -216
  55. package/tests/setupVitest.ts +0 -6
  56. package/tests/ui-environment.test.ts +0 -97
  57. package/tests/ui-prompts.test.ts +0 -205
  58. package/tests-e2e/addons-smoke.spec.ts +0 -31
  59. package/tests-e2e/create-smoke.spec.ts +0 -39
  60. package/tests-e2e/helpers.ts +0 -526
  61. package/tests-e2e/matrix-opportunistic.spec.ts +0 -142
  62. package/tests-e2e/router-only-smoke.spec.ts +0 -68
  63. package/tests-e2e/solid-smoke.spec.ts +0 -25
  64. package/tests-e2e/templates-smoke.spec.ts +0 -52
  65. package/tsconfig.json +0 -17
  66. package/vitest.config.js +0 -8
package/src/ui-prompts.ts DELETED
@@ -1,355 +0,0 @@
1
- import {
2
- cancel,
3
- confirm,
4
- isCancel,
5
- multiselect,
6
- note,
7
- password,
8
- select,
9
- text,
10
- } from '@clack/prompts'
11
-
12
- import {
13
- DEFAULT_PACKAGE_MANAGER,
14
- SUPPORTED_PACKAGE_MANAGERS,
15
- getAllAddOns,
16
- } from '@tanstack/create'
17
-
18
- import { validateProjectName } from './utils.js'
19
- import type { AddOn, PackageManager } from '@tanstack/create'
20
-
21
- import type { Framework } from '@tanstack/create/dist/types/types.js'
22
-
23
- export async function getProjectName(): Promise<string> {
24
- const value = await text({
25
- message: 'What would you like to name your project?',
26
- defaultValue: 'my-app',
27
- validate(value) {
28
- if (!value) {
29
- return 'Please enter a name'
30
- }
31
-
32
- const { valid, error } = validateProjectName(value)
33
- if (!valid) {
34
- return error
35
- }
36
- },
37
- })
38
-
39
- if (isCancel(value)) {
40
- cancel('Operation cancelled.')
41
- process.exit(0)
42
- }
43
-
44
- return value
45
- }
46
-
47
- export async function selectPackageManager(): Promise<PackageManager> {
48
- const packageManager = await select({
49
- message: 'Select package manager:',
50
- options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
51
- value: pm,
52
- label: pm,
53
- })),
54
- initialValue: DEFAULT_PACKAGE_MANAGER,
55
- })
56
- if (isCancel(packageManager)) {
57
- cancel('Operation cancelled.')
58
- process.exit(0)
59
- }
60
- return packageManager
61
- }
62
-
63
- // Track if we've shown the multiselect help text
64
- let hasShownMultiselectHelp = false
65
-
66
- export async function selectAddOns(
67
- framework: Framework,
68
- mode: string,
69
- type: string,
70
- message: string,
71
- forcedAddOns: Array<string> = [],
72
- allowMultiple: boolean = true,
73
- ): Promise<Array<string>> {
74
- const allAddOns = await getAllAddOns(framework, mode)
75
- const addOns = allAddOns.filter((addOn) => addOn.type === type)
76
- if (addOns.length === 0) {
77
- return []
78
- }
79
-
80
- // Show help text only once
81
- if (!hasShownMultiselectHelp) {
82
- note(
83
- 'Use ↑/↓ to navigate • Space to select/deselect • Enter to confirm',
84
- 'Keyboard Shortcuts',
85
- )
86
- hasShownMultiselectHelp = true
87
- }
88
-
89
- if (allowMultiple) {
90
- const selectableAddOns = addOns.filter(
91
- (addOn) => !forcedAddOns.includes(addOn.id),
92
- )
93
-
94
- if (selectableAddOns.length === 0) {
95
- return []
96
- }
97
-
98
- const value = await multiselect({
99
- message,
100
- options: selectableAddOns.map((addOn) => ({
101
- value: addOn.id,
102
- label: addOn.name,
103
- hint: addOn.description,
104
- })),
105
- maxItems: selectableAddOns.length,
106
- required: false,
107
- })
108
-
109
- if (isCancel(value)) {
110
- cancel('Operation cancelled.')
111
- process.exit(0)
112
- }
113
-
114
- return value
115
- } else {
116
- const value = await select({
117
- message,
118
- options: [
119
- {
120
- value: 'none',
121
- label: 'None',
122
- },
123
- ...addOns
124
- .filter((addOn) => !forcedAddOns.includes(addOn.id))
125
- .map((addOn) => ({
126
- value: addOn.id,
127
- label: addOn.name,
128
- hint: addOn.description,
129
- })),
130
- ],
131
- initialValue: 'none',
132
- })
133
-
134
- if (isCancel(value)) {
135
- cancel('Operation cancelled.')
136
- process.exit(0)
137
- }
138
-
139
- return value === 'none' ? [] : [value]
140
- }
141
- }
142
-
143
- export async function selectGit(): Promise<boolean> {
144
- const git = await confirm({
145
- message: 'Would you like to initialize a new git repository?',
146
- initialValue: true,
147
- })
148
- if (isCancel(git)) {
149
- cancel('Operation cancelled.')
150
- process.exit(0)
151
- }
152
- return git
153
- }
154
-
155
- export async function selectExamples(): Promise<boolean> {
156
- const includeExamples = await confirm({
157
- message: 'Would you like to include demo/example pages?',
158
- initialValue: true,
159
- })
160
- if (isCancel(includeExamples)) {
161
- cancel('Operation cancelled.')
162
- process.exit(0)
163
- }
164
- return includeExamples
165
- }
166
-
167
- export async function selectToolchain(
168
- framework: Framework,
169
- toolchain?: string | false,
170
- ): Promise<string | undefined> {
171
- if (toolchain === false) {
172
- return undefined
173
- }
174
-
175
- const toolchains = new Set<AddOn>()
176
- for (const addOn of framework.getAddOns()) {
177
- if (addOn.type === 'toolchain') {
178
- toolchains.add(addOn)
179
- if (toolchain && addOn.id === toolchain) {
180
- return toolchain
181
- }
182
- }
183
- }
184
-
185
- const tc = await select({
186
- message: 'Select toolchain',
187
- options: [
188
- {
189
- value: undefined,
190
- label: 'None',
191
- },
192
- ...Array.from(toolchains).map((tc) => ({
193
- value: tc.id,
194
- label: tc.name,
195
- })),
196
- ],
197
- initialValue: undefined,
198
- })
199
-
200
- if (isCancel(tc)) {
201
- cancel('Operation cancelled.')
202
- process.exit(0)
203
- }
204
-
205
- return tc
206
- }
207
-
208
- export async function promptForAddOnOptions(
209
- addOnIds: Array<string>,
210
- framework: Framework,
211
- ): Promise<Record<string, Record<string, any>>> {
212
- const addOnOptions: Record<string, Record<string, any>> = {}
213
-
214
- for (const addOnId of addOnIds) {
215
- const addOn = framework.getAddOns().find((a) => a.id === addOnId)
216
- if (!addOn || !addOn.options) continue
217
-
218
- addOnOptions[addOnId] = {}
219
-
220
- for (const [optionName, option] of Object.entries(addOn.options)) {
221
- if (option && typeof option === 'object' && 'type' in option) {
222
- if (option.type === 'select') {
223
- const selectOption = option as {
224
- type: 'select'
225
- label: string
226
- description?: string
227
- default: string
228
- options: Array<{ value: string; label: string }>
229
- }
230
-
231
- const value = await select({
232
- message: `${addOn.name}: ${selectOption.label}`,
233
- options: selectOption.options.map((opt) => ({
234
- value: opt.value,
235
- label: opt.label,
236
- })),
237
- initialValue: selectOption.default,
238
- })
239
-
240
- if (isCancel(value)) {
241
- cancel('Operation cancelled.')
242
- process.exit(0)
243
- }
244
-
245
- addOnOptions[addOnId][optionName] = value
246
- }
247
- // Future option types can be added here
248
- }
249
- }
250
- }
251
-
252
- return addOnOptions
253
- }
254
-
255
- export async function promptForEnvVars(
256
- addOns: Array<AddOn>,
257
- ): Promise<Record<string, string>> {
258
- const envVars = new Map<
259
- string,
260
- {
261
- name: string
262
- description?: string
263
- required?: boolean
264
- default?: string
265
- secret?: boolean
266
- }
267
- >()
268
-
269
- for (const addOn of addOns as Array<any>) {
270
- for (const envVar of addOn.envVars || []) {
271
- if (!envVars.has(envVar.name)) {
272
- envVars.set(envVar.name, envVar)
273
- }
274
- }
275
- }
276
-
277
- const result: Record<string, string> = {}
278
-
279
- for (const envVar of envVars.values()) {
280
- const label = envVar.description
281
- ? `${envVar.name} (${envVar.description})`
282
- : envVar.name
283
-
284
- const value = envVar.secret
285
- ? await password({
286
- message: `Enter ${label}`,
287
- validate: envVar.required
288
- ? (v) =>
289
- v && v.trim().length > 0
290
- ? undefined
291
- : `${envVar.name} is required`
292
- : undefined,
293
- })
294
- : await text({
295
- message: `Enter ${label}`,
296
- defaultValue: envVar.default,
297
- validate: envVar.required
298
- ? (v) =>
299
- v && v.trim().length > 0
300
- ? undefined
301
- : `${envVar.name} is required`
302
- : undefined,
303
- })
304
-
305
- if (isCancel(value)) {
306
- cancel('Operation cancelled.')
307
- process.exit(0)
308
- }
309
-
310
- if (value && value.trim()) {
311
- result[envVar.name] = value.trim()
312
- }
313
- }
314
-
315
- return result
316
- }
317
-
318
- export async function selectDeployment(
319
- framework: Framework,
320
- deployment?: string,
321
- ): Promise<string | undefined> {
322
- const deployments = new Set<AddOn>()
323
- let initialValue: string | undefined = undefined
324
- for (const addOn of framework
325
- .getAddOns()
326
- .sort((a, b) => a.name.localeCompare(b.name))) {
327
- if (addOn.type === 'deployment') {
328
- deployments.add(addOn)
329
- if (deployment && addOn.id === deployment) {
330
- return deployment
331
- }
332
- if (addOn.default) {
333
- initialValue = addOn.id
334
- }
335
- }
336
- }
337
-
338
- const dp = await select({
339
- message: 'Select deployment adapter',
340
- options: [
341
- ...Array.from(deployments).map((d) => ({
342
- value: d.id,
343
- label: d.name,
344
- })),
345
- ],
346
- initialValue: initialValue,
347
- })
348
-
349
- if (isCancel(dp)) {
350
- cancel('Operation cancelled.')
351
- process.exit(0)
352
- }
353
-
354
- return dp
355
- }
package/src/utils.ts DELETED
@@ -1,30 +0,0 @@
1
- import { basename } from 'node:path'
2
- import validatePackageName from 'validate-npm-package-name'
3
-
4
- export function sanitizePackageName(name: string): string {
5
- return name
6
- .toLowerCase()
7
- .replace(/\s+/g, '-') // Replace spaces with hyphens
8
- .replace(/_/g, '-') // Replace underscores with hyphens
9
- .replace(/[^a-z0-9-]/g, '') // Remove invalid characters
10
- .replace(/^[^a-z]+/, '') // Ensure it starts with a letter
11
- .replace(/-+/g, '-') // Collapse multiple hyphens
12
- .replace(/-$/, '') // Remove trailing hyphen
13
- }
14
-
15
- export function getCurrentDirectoryName(): string {
16
- return basename(process.cwd())
17
- }
18
-
19
- export function validateProjectName(name: string) {
20
- const { validForNewPackages, validForOldPackages, errors, warnings } =
21
- validatePackageName(name)
22
- const error = errors?.[0] || warnings?.[0]
23
-
24
- return {
25
- valid: validForNewPackages && validForOldPackages,
26
- error:
27
- error?.replace(/name/g, 'Project name') ||
28
- 'Project name does not meet npm package naming requirements',
29
- }
30
- }
@@ -1,4 +0,0 @@
1
- {
2
- "status": "passed",
3
- "failedTests": []
4
- }