@tanstack/cta-cli 0.46.2 → 0.47.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/CHANGELOG.md +15 -0
- package/dist/cli.js +61 -4
- package/dist/command-line.js +57 -1
- package/dist/dev-watch.js +290 -0
- package/dist/file-syncer.js +148 -0
- package/dist/options.js +19 -8
- package/dist/types/cli.d.ts +3 -1
- package/dist/types/command-line.d.ts +4 -0
- package/dist/types/dev-watch.d.ts +27 -0
- package/dist/types/file-syncer.d.ts +18 -0
- package/dist/types/types.d.ts +2 -0
- package/package.json +8 -3
- package/src/cli.ts +83 -3
- package/src/command-line.ts +69 -1
- package/src/dev-watch.ts +430 -0
- package/src/file-syncer.ts +205 -0
- package/src/options.ts +21 -8
- package/src/types.ts +2 -0
- package/tests/command-line.test.ts +6 -2
- package/tests/options.test.ts +5 -0
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TemplateOptions } from './types.js';
|
|
2
|
-
|
|
2
|
+
import type { FrameworkDefinition } from '@tanstack/cta-engine';
|
|
3
|
+
export declare function cli({ name, appName, forcedMode, forcedAddOns, defaultTemplate, forcedDeployment, defaultFramework, craCompatible, webBase, frameworkDefinitionInitializers, showDeploymentOptions, }: {
|
|
3
4
|
name: string;
|
|
4
5
|
appName: string;
|
|
5
6
|
forcedMode?: string;
|
|
@@ -9,5 +10,6 @@ export declare function cli({ name, appName, forcedMode, forcedAddOns, defaultTe
|
|
|
9
10
|
defaultFramework?: string;
|
|
10
11
|
craCompatible?: boolean;
|
|
11
12
|
webBase?: string;
|
|
13
|
+
frameworkDefinitionInitializers?: Array<() => FrameworkDefinition>;
|
|
12
14
|
showDeploymentOptions?: boolean;
|
|
13
15
|
}): void;
|
|
@@ -4,3 +4,7 @@ export declare function normalizeOptions(cliOptions: CliOptions, forcedMode?: st
|
|
|
4
4
|
disableNameCheck?: boolean;
|
|
5
5
|
forcedDeployment?: string;
|
|
6
6
|
}): Promise<Options | undefined>;
|
|
7
|
+
export declare function validateDevWatchOptions(cliOptions: CliOptions): {
|
|
8
|
+
valid: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Environment, Framework, FrameworkDefinition, Options } from '@tanstack/cta-engine';
|
|
2
|
+
export interface DevWatchOptions {
|
|
3
|
+
watchPath: string;
|
|
4
|
+
targetDir: string;
|
|
5
|
+
framework: Framework;
|
|
6
|
+
cliOptions: Options;
|
|
7
|
+
packageManager: string;
|
|
8
|
+
environment: Environment;
|
|
9
|
+
frameworkDefinitionInitializers?: Array<() => FrameworkDefinition>;
|
|
10
|
+
}
|
|
11
|
+
export declare class DevWatchManager {
|
|
12
|
+
private options;
|
|
13
|
+
private watcher;
|
|
14
|
+
private debounceQueue;
|
|
15
|
+
private syncer;
|
|
16
|
+
private tempDir;
|
|
17
|
+
private isBuilding;
|
|
18
|
+
private buildCount;
|
|
19
|
+
constructor(options: DevWatchOptions);
|
|
20
|
+
start(): Promise<void>;
|
|
21
|
+
stop(): Promise<void>;
|
|
22
|
+
private startWatcher;
|
|
23
|
+
private handleChange;
|
|
24
|
+
private rebuild;
|
|
25
|
+
private cleanup;
|
|
26
|
+
private log;
|
|
27
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface FileUpdate {
|
|
2
|
+
path: string;
|
|
3
|
+
diff?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SyncResult {
|
|
6
|
+
updated: Array<FileUpdate>;
|
|
7
|
+
skipped: Array<string>;
|
|
8
|
+
created: Array<string>;
|
|
9
|
+
errors: Array<string>;
|
|
10
|
+
}
|
|
11
|
+
export declare class FileSyncer {
|
|
12
|
+
sync(sourceDir: string, targetDir: string): Promise<SyncResult>;
|
|
13
|
+
private syncDirectory;
|
|
14
|
+
private shouldUpdateFile;
|
|
15
|
+
private calculateHash;
|
|
16
|
+
private shouldSkipDirectory;
|
|
17
|
+
private shouldSkipFile;
|
|
18
|
+
}
|
package/dist/types/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/cta-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Tanstack Application Builder CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,15 +27,20 @@
|
|
|
27
27
|
"@clack/prompts": "^0.10.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.6.0",
|
|
29
29
|
"chalk": "^5.4.1",
|
|
30
|
+
"chokidar": "^3.6.0",
|
|
30
31
|
"commander": "^13.1.0",
|
|
32
|
+
"diff": "^7.0.0",
|
|
31
33
|
"express": "^4.21.2",
|
|
32
34
|
"semver": "^7.7.2",
|
|
35
|
+
"tempy": "^3.1.0",
|
|
33
36
|
"validate-npm-package-name": "^7.0.0",
|
|
34
37
|
"zod": "^3.24.2",
|
|
35
|
-
"@tanstack/cta-engine": "0.
|
|
36
|
-
"@tanstack/cta-ui": "0.
|
|
38
|
+
"@tanstack/cta-engine": "0.47.0",
|
|
39
|
+
"@tanstack/cta-ui": "0.47.0"
|
|
37
40
|
},
|
|
38
41
|
"devDependencies": {
|
|
42
|
+
"@tanstack/config": "^0.16.2",
|
|
43
|
+
"@types/diff": "^5.2.0",
|
|
39
44
|
"@types/express": "^5.0.1",
|
|
40
45
|
"@types/node": "^22.13.4",
|
|
41
46
|
"@types/semver": "^7.7.0",
|
package/src/cli.ts
CHANGED
|
@@ -24,13 +24,18 @@ import { launchUI } from '@tanstack/cta-ui'
|
|
|
24
24
|
import { runMCPServer } from './mcp.js'
|
|
25
25
|
|
|
26
26
|
import { promptForAddOns, promptForCreateOptions } from './options.js'
|
|
27
|
-
import { normalizeOptions } from './command-line.js'
|
|
27
|
+
import { normalizeOptions, validateDevWatchOptions } from './command-line.js'
|
|
28
28
|
|
|
29
29
|
import { createUIEnvironment } from './ui-environment.js'
|
|
30
30
|
import { convertTemplateToMode } from './utils.js'
|
|
31
|
+
import { DevWatchManager } from './dev-watch.js'
|
|
31
32
|
|
|
32
33
|
import type { CliOptions, TemplateOptions } from './types.js'
|
|
33
|
-
import type {
|
|
34
|
+
import type {
|
|
35
|
+
FrameworkDefinition,
|
|
36
|
+
Options,
|
|
37
|
+
PackageManager,
|
|
38
|
+
} from '@tanstack/cta-engine'
|
|
34
39
|
|
|
35
40
|
// This CLI assumes that all of the registered frameworks have the same set of toolchains, deployments, modes, etc.
|
|
36
41
|
|
|
@@ -44,6 +49,7 @@ export function cli({
|
|
|
44
49
|
defaultFramework,
|
|
45
50
|
craCompatible = false,
|
|
46
51
|
webBase,
|
|
52
|
+
frameworkDefinitionInitializers,
|
|
47
53
|
showDeploymentOptions = false,
|
|
48
54
|
}: {
|
|
49
55
|
name: string
|
|
@@ -55,6 +61,7 @@ export function cli({
|
|
|
55
61
|
defaultFramework?: string
|
|
56
62
|
craCompatible?: boolean
|
|
57
63
|
webBase?: string
|
|
64
|
+
frameworkDefinitionInitializers?: Array<() => FrameworkDefinition>
|
|
58
65
|
showDeploymentOptions?: boolean
|
|
59
66
|
}) {
|
|
60
67
|
const environment = createUIEnvironment(appName, false)
|
|
@@ -293,6 +300,7 @@ Remove your node_modules directory and package lock file and re-install.`,
|
|
|
293
300
|
'initialize this project from a starter URL',
|
|
294
301
|
false,
|
|
295
302
|
)
|
|
303
|
+
.option('--no-install', 'skip installing dependencies')
|
|
296
304
|
.option<PackageManager>(
|
|
297
305
|
`--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`,
|
|
298
306
|
`Explicitly tell the CLI to use this package manager`,
|
|
@@ -307,6 +315,10 @@ Remove your node_modules directory and package lock file and re-install.`,
|
|
|
307
315
|
return value as PackageManager
|
|
308
316
|
},
|
|
309
317
|
)
|
|
318
|
+
.option(
|
|
319
|
+
'--dev-watch <path>',
|
|
320
|
+
'Watch a framework directory for changes and auto-rebuild',
|
|
321
|
+
)
|
|
310
322
|
|
|
311
323
|
if (deployments.size > 0) {
|
|
312
324
|
program.option<string>(
|
|
@@ -344,7 +356,8 @@ Remove your node_modules directory and package lock file and re-install.`,
|
|
|
344
356
|
|
|
345
357
|
program
|
|
346
358
|
.option('--interactive', 'interactive mode', false)
|
|
347
|
-
.option('--tailwind', 'add Tailwind CSS'
|
|
359
|
+
.option('--tailwind', 'add Tailwind CSS')
|
|
360
|
+
.option('--no-tailwind', 'skip Tailwind CSS')
|
|
348
361
|
.option<Array<string> | boolean>(
|
|
349
362
|
'--add-ons [...add-ons]',
|
|
350
363
|
'pick from a list of available add-ons (comma separated list)',
|
|
@@ -462,6 +475,73 @@ Remove your node_modules directory and package lock file and re-install.`,
|
|
|
462
475
|
forcedAddOns,
|
|
463
476
|
appName,
|
|
464
477
|
})
|
|
478
|
+
} else if (options.devWatch) {
|
|
479
|
+
// Validate dev watch options
|
|
480
|
+
const validation = validateDevWatchOptions({ ...options, projectName })
|
|
481
|
+
if (!validation.valid) {
|
|
482
|
+
console.error(validation.error)
|
|
483
|
+
process.exit(1)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Enter dev watch mode
|
|
487
|
+
if (!projectName && !options.targetDir) {
|
|
488
|
+
console.error(
|
|
489
|
+
'Project name/target directory is required for dev watch mode',
|
|
490
|
+
)
|
|
491
|
+
process.exit(1)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (!options.framework) {
|
|
495
|
+
console.error('Failed to detect framework')
|
|
496
|
+
process.exit(1)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const framework = getFrameworkByName(options.framework)
|
|
500
|
+
if (!framework) {
|
|
501
|
+
console.error('Failed to detect framework')
|
|
502
|
+
process.exit(1)
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// First, create the app normally using the standard flow
|
|
506
|
+
const normalizedOpts = await normalizeOptions(
|
|
507
|
+
{
|
|
508
|
+
...options,
|
|
509
|
+
projectName,
|
|
510
|
+
framework: framework.id,
|
|
511
|
+
},
|
|
512
|
+
defaultMode,
|
|
513
|
+
forcedAddOns,
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
if (!normalizedOpts) {
|
|
517
|
+
throw new Error('Failed to normalize options')
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
normalizedOpts.targetDir =
|
|
521
|
+
options.targetDir || resolve(process.cwd(), projectName)
|
|
522
|
+
|
|
523
|
+
// Create the initial app with minimal output for dev watch mode
|
|
524
|
+
console.log(chalk.bold('\ndev-watch'))
|
|
525
|
+
console.log(chalk.gray('├─') + ' ' + `creating initial ${appName} app...`)
|
|
526
|
+
if (normalizedOpts.install !== false) {
|
|
527
|
+
console.log(chalk.gray('├─') + ' ' + chalk.yellow('⟳') + ' installing packages...')
|
|
528
|
+
}
|
|
529
|
+
const silentEnvironment = createUIEnvironment(appName, true)
|
|
530
|
+
await createApp(silentEnvironment, normalizedOpts)
|
|
531
|
+
console.log(chalk.gray('└─') + ' ' + chalk.green('✓') + ` app created`)
|
|
532
|
+
|
|
533
|
+
// Now start the dev watch mode
|
|
534
|
+
const manager = new DevWatchManager({
|
|
535
|
+
watchPath: options.devWatch,
|
|
536
|
+
targetDir: normalizedOpts.targetDir,
|
|
537
|
+
framework,
|
|
538
|
+
cliOptions: normalizedOpts,
|
|
539
|
+
packageManager: normalizedOpts.packageManager,
|
|
540
|
+
environment,
|
|
541
|
+
frameworkDefinitionInitializers,
|
|
542
|
+
})
|
|
543
|
+
|
|
544
|
+
await manager.start()
|
|
465
545
|
} else {
|
|
466
546
|
try {
|
|
467
547
|
const cliOptions = {
|
package/src/command-line.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
|
+
import fs from 'node:fs'
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
5
|
DEFAULT_PACKAGE_MANAGER,
|
|
@@ -131,8 +132,25 @@ export async function normalizeOptions(
|
|
|
131
132
|
const chosenAddOns = await selectAddOns()
|
|
132
133
|
|
|
133
134
|
if (chosenAddOns.length) {
|
|
134
|
-
tailwind = true
|
|
135
135
|
typescript = true
|
|
136
|
+
|
|
137
|
+
// Check if any add-on explicitly requires tailwind
|
|
138
|
+
const addOnsRequireTailwind = chosenAddOns.some(
|
|
139
|
+
(addOn) => addOn.tailwind === true,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
// Only set tailwind to true if:
|
|
143
|
+
// 1. An add-on explicitly requires it, OR
|
|
144
|
+
// 2. User explicitly set it via CLI
|
|
145
|
+
if (addOnsRequireTailwind) {
|
|
146
|
+
tailwind = true
|
|
147
|
+
} else if (cliOptions.tailwind === true) {
|
|
148
|
+
tailwind = true
|
|
149
|
+
} else if (cliOptions.tailwind === false) {
|
|
150
|
+
tailwind = false
|
|
151
|
+
}
|
|
152
|
+
// If cliOptions.tailwind is undefined and no add-ons require it,
|
|
153
|
+
// leave tailwind as is (will be prompted in interactive mode)
|
|
136
154
|
}
|
|
137
155
|
|
|
138
156
|
// Handle add-on configuration option
|
|
@@ -158,6 +176,7 @@ export async function normalizeOptions(
|
|
|
158
176
|
getPackageManager() ||
|
|
159
177
|
DEFAULT_PACKAGE_MANAGER,
|
|
160
178
|
git: !!cliOptions.git,
|
|
179
|
+
install: cliOptions.install,
|
|
161
180
|
chosenAddOns,
|
|
162
181
|
addOnOptions: {
|
|
163
182
|
...populateAddOnOptionsDefaults(chosenAddOns),
|
|
@@ -166,3 +185,52 @@ export async function normalizeOptions(
|
|
|
166
185
|
starter: starter,
|
|
167
186
|
}
|
|
168
187
|
}
|
|
188
|
+
|
|
189
|
+
export function validateDevWatchOptions(cliOptions: CliOptions): {
|
|
190
|
+
valid: boolean
|
|
191
|
+
error?: string
|
|
192
|
+
} {
|
|
193
|
+
if (!cliOptions.devWatch) {
|
|
194
|
+
return { valid: true }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Validate watch path exists
|
|
198
|
+
const watchPath = resolve(process.cwd(), cliOptions.devWatch)
|
|
199
|
+
if (!fs.existsSync(watchPath)) {
|
|
200
|
+
return {
|
|
201
|
+
valid: false,
|
|
202
|
+
error: `Watch path does not exist: ${watchPath}`,
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Validate it's a directory
|
|
207
|
+
const stats = fs.statSync(watchPath)
|
|
208
|
+
if (!stats.isDirectory()) {
|
|
209
|
+
return {
|
|
210
|
+
valid: false,
|
|
211
|
+
error: `Watch path is not a directory: ${watchPath}`,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Ensure target directory is specified
|
|
216
|
+
if (!cliOptions.projectName && !cliOptions.targetDir) {
|
|
217
|
+
return {
|
|
218
|
+
valid: false,
|
|
219
|
+
error: 'Project name or target directory is required for dev watch mode',
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Check for framework structure
|
|
224
|
+
const hasAddOns = fs.existsSync(resolve(watchPath, 'add-ons'))
|
|
225
|
+
const hasAssets = fs.existsSync(resolve(watchPath, 'assets'))
|
|
226
|
+
const hasFrameworkJson = fs.existsSync(resolve(watchPath, 'framework.json'))
|
|
227
|
+
|
|
228
|
+
if (!hasAddOns && !hasAssets && !hasFrameworkJson) {
|
|
229
|
+
return {
|
|
230
|
+
valid: false,
|
|
231
|
+
error: `Watch path does not appear to be a valid framework directory: ${watchPath}`,
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return { valid: true }
|
|
236
|
+
}
|