@lenne.tech/cli 1.13.0 → 1.15.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 +31 -0
- package/build/commands/fullstack/init.js +85 -29
- package/build/commands/server/create.js +53 -26
- package/build/extensions/server.js +72 -43
- package/build/extensions/tools.js +12 -1
- package/build/templates/next-fullstack/.claude/QUICKSTART.md.ejs +61 -0
- package/build/templates/next-fullstack/CLAUDE.md.ejs +45 -0
- package/build/templates/next-fullstack/README.md.ejs +48 -0
- package/docs/LT-ECOSYSTEM-GUIDE.md +1 -0
- package/docs/commands.md +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,6 +94,37 @@ $ lt fullstack init --name myapp --framework-mode vendor --dry-run --noConfirm
|
|
|
94
94
|
$ lt server create --name myapp --framework-mode vendor
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
### Experimental: `--next` (nest-base)
|
|
98
|
+
|
|
99
|
+
Both `lt fullstack init` and `lt server create` support an experimental
|
|
100
|
+
`--next` flag that swaps the API template from
|
|
101
|
+
[`nest-server-starter`](https://github.com/lenneTech/nest-server-starter)
|
|
102
|
+
(MongoDB) to [`nest-base`](https://github.com/lenneTech/nest-base) — a new
|
|
103
|
+
NestJS stack on **Bun + Prisma 7 + Postgres + Better-Auth** with a built-in
|
|
104
|
+
`/dev` cockpit.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# experimental standalone api
|
|
108
|
+
$ lt server create my-next-api --next --noConfirm
|
|
109
|
+
|
|
110
|
+
# experimental fullstack (nuxt + nest-base)
|
|
111
|
+
$ lt fullstack init --name my-next-app --frontend nuxt --next --noConfirm
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
When `--next` is set the CLI:
|
|
115
|
+
|
|
116
|
+
- clones `nest-base` instead of `nest-server-starter`,
|
|
117
|
+
- forces `--api-mode Rest` and `--framework-mode npm` (other modes are not
|
|
118
|
+
applicable to nest-base),
|
|
119
|
+
- skips `nest-server-starter`-specific patching (`config.env.ts`,
|
|
120
|
+
`main.ts` Swagger setup, `meta.json`, `lt.config.json`),
|
|
121
|
+
- skips the workspace install in fullstack mode — run `pnpm install` for
|
|
122
|
+
the frontend and `bun install` for the API yourself.
|
|
123
|
+
|
|
124
|
+
This option is **experimental** and may change. The downstream `lt server
|
|
125
|
+
module/object/addProp/test/permissions` commands target the classic
|
|
126
|
+
`nest-server` layout and are not yet compatible with `nest-base`.
|
|
127
|
+
|
|
97
128
|
### Working on an existing project
|
|
98
129
|
|
|
99
130
|
All `lt server …` commands (module, object, addProp, test, permissions)
|
|
@@ -21,13 +21,13 @@ const NewCommand = {
|
|
|
21
21
|
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
22
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
23
23
|
// Retrieve the tools we need
|
|
24
|
-
const { config, filesystem, frontendHelper, git, helper, parameters, patching, print: { error, info, spin, success }, prompt: { ask, confirm }, server, strings: { kebabCase }, system, } = toolbox;
|
|
24
|
+
const { config, filesystem, frontendHelper, git, helper, parameters, patching, print: { error, info, spin, success }, prompt: { ask, confirm }, server, strings: { kebabCase }, system, template, } = toolbox;
|
|
25
25
|
// Start timer
|
|
26
26
|
const timer = system.startTimer();
|
|
27
27
|
// Info
|
|
28
28
|
info('Create a new fullstack workspace');
|
|
29
29
|
// Hint for non-interactive callers (e.g. Claude Code)
|
|
30
|
-
toolbox.tools.nonInteractiveHint('lt fullstack init --name <name> --frontend <nuxt|angular> --api-mode <Rest|GraphQL|Both> --framework-mode <npm|vendor> [--framework-upstream-branch <ref>] [--dry-run] --noConfirm');
|
|
30
|
+
toolbox.tools.nonInteractiveHint('lt fullstack init --name <name> --frontend <nuxt|angular> --api-mode <Rest|GraphQL|Both> --framework-mode <npm|vendor> [--framework-upstream-branch <ref>] [--next] [--dry-run] --noConfirm');
|
|
31
31
|
// Check git
|
|
32
32
|
if (!(yield git.gitInstalled())) {
|
|
33
33
|
return;
|
|
@@ -46,8 +46,9 @@ const NewCommand = {
|
|
|
46
46
|
const configFrontendLink = (_v = (_u = ltConfig === null || ltConfig === void 0 ? void 0 : ltConfig.commands) === null || _u === void 0 ? void 0 : _u.fullstack) === null || _v === void 0 ? void 0 : _v.frontendLink;
|
|
47
47
|
const configFrameworkMode = (_x = (_w = ltConfig === null || ltConfig === void 0 ? void 0 : ltConfig.commands) === null || _w === void 0 ? void 0 : _w.fullstack) === null || _x === void 0 ? void 0 : _x.frameworkMode;
|
|
48
48
|
// Parse CLI arguments
|
|
49
|
-
const { 'api-branch': cliApiBranch, 'api-copy': cliApiCopy, 'api-link': cliApiLink, 'api-mode': cliApiMode, 'dry-run': cliDryRun, 'framework-mode': cliFrameworkMode, 'framework-upstream-branch': cliFrameworkUpstreamBranch, frontend: cliFrontend, 'frontend-branch': cliFrontendBranch, 'frontend-copy': cliFrontendCopy, 'frontend-framework-mode': cliFrontendFrameworkMode, 'frontend-link': cliFrontendLink, git: cliGit, 'git-link': cliGitLink, name: cliName, } = parameters.options;
|
|
49
|
+
const { 'api-branch': cliApiBranch, 'api-copy': cliApiCopy, 'api-link': cliApiLink, 'api-mode': cliApiMode, 'dry-run': cliDryRun, 'framework-mode': cliFrameworkMode, 'framework-upstream-branch': cliFrameworkUpstreamBranch, frontend: cliFrontend, 'frontend-branch': cliFrontendBranch, 'frontend-copy': cliFrontendCopy, 'frontend-framework-mode': cliFrontendFrameworkMode, 'frontend-link': cliFrontendLink, git: cliGit, 'git-link': cliGitLink, name: cliName, next: cliNext, } = parameters.options;
|
|
50
50
|
const dryRun = cliDryRun === true || cliDryRun === 'true';
|
|
51
|
+
const experimental = cliNext === true || cliNext === 'true';
|
|
51
52
|
const frameworkUpstreamBranch = typeof cliFrameworkUpstreamBranch === 'string' && cliFrameworkUpstreamBranch.length > 0
|
|
52
53
|
? cliFrameworkUpstreamBranch
|
|
53
54
|
: undefined;
|
|
@@ -109,7 +110,11 @@ const NewCommand = {
|
|
|
109
110
|
// Determine API mode with priority: CLI > config > global > interactive (default: Rest)
|
|
110
111
|
const globalApiMode = config.getGlobalDefault(ltConfig, 'apiMode');
|
|
111
112
|
let apiMode;
|
|
112
|
-
if (
|
|
113
|
+
if (experimental) {
|
|
114
|
+
apiMode = 'Rest';
|
|
115
|
+
info('Using experimental nest-base template (Bun + Prisma + Postgres + Better-Auth)');
|
|
116
|
+
}
|
|
117
|
+
else if (cliApiMode) {
|
|
113
118
|
apiMode = cliApiMode;
|
|
114
119
|
}
|
|
115
120
|
else if (configApiMode) {
|
|
@@ -154,7 +159,10 @@ const NewCommand = {
|
|
|
154
159
|
//
|
|
155
160
|
// Default is still 'npm' until the vendoring pilot is fully evaluated.
|
|
156
161
|
let frameworkMode;
|
|
157
|
-
if (
|
|
162
|
+
if (experimental) {
|
|
163
|
+
frameworkMode = 'npm';
|
|
164
|
+
}
|
|
165
|
+
else if (cliFrameworkMode === 'npm' || cliFrameworkMode === 'vendor') {
|
|
158
166
|
frameworkMode = cliFrameworkMode;
|
|
159
167
|
}
|
|
160
168
|
else if (cliFrameworkMode) {
|
|
@@ -291,7 +299,10 @@ const NewCommand = {
|
|
|
291
299
|
info('Would execute:');
|
|
292
300
|
info(` 1. git clone lt-monorepo → ${projectDir}/`);
|
|
293
301
|
info(` 2. setup frontend (${frontend}) → ${projectDir}/projects/app`);
|
|
294
|
-
if (
|
|
302
|
+
if (experimental) {
|
|
303
|
+
info(` 3. clone nest-base (experimental) → ${projectDir}/projects/api`);
|
|
304
|
+
}
|
|
305
|
+
else if (frameworkMode === 'vendor') {
|
|
295
306
|
info(` 3. clone nest-server-starter → ${projectDir}/projects/api`);
|
|
296
307
|
info(` 4. clone @lenne.tech/nest-server${frameworkUpstreamBranch ? ` (branch/tag: ${frameworkUpstreamBranch})` : ''} → /tmp`);
|
|
297
308
|
info(` 5. vendor core/ + flatten-fix + codemod consumer imports`);
|
|
@@ -333,16 +344,46 @@ const NewCommand = {
|
|
|
333
344
|
const ngBaseSpinner = spin(`Integrate example for ${frontend}`);
|
|
334
345
|
// Remove git folder after clone
|
|
335
346
|
filesystem.remove(`${projectDir}/.git`);
|
|
336
|
-
// Patch
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
347
|
+
// Patch root files for the project.
|
|
348
|
+
//
|
|
349
|
+
// For the classic flow we patch the cloned `lt-monorepo` CLAUDE.md with
|
|
350
|
+
// template variables. For `--next` (experimental) we replace the root
|
|
351
|
+
// README.md, CLAUDE.md, and create `.claude/QUICKSTART.md` outright,
|
|
352
|
+
// because `lt-monorepo`'s root files describe the legacy MongoDB +
|
|
353
|
+
// GraphQL stack which is explicitly out of scope for the nest-base
|
|
354
|
+
// template — leaving them in place poisons every AI agent's context.
|
|
355
|
+
if (experimental) {
|
|
356
|
+
const nextTemplateProps = { name, projectDir };
|
|
357
|
+
// Render new root files. `template.generate({ target })` overwrites
|
|
358
|
+
// anything at `target`, which is what we want — the freshly cloned
|
|
359
|
+
// monorepo's stale README/CLAUDE.md must be replaced wholesale.
|
|
360
|
+
yield template.generate({
|
|
361
|
+
props: nextTemplateProps,
|
|
362
|
+
target: `${projectDir}/README.md`,
|
|
363
|
+
template: 'next-fullstack/README.md.ejs',
|
|
364
|
+
});
|
|
365
|
+
yield template.generate({
|
|
366
|
+
props: nextTemplateProps,
|
|
367
|
+
target: `${projectDir}/CLAUDE.md`,
|
|
368
|
+
template: 'next-fullstack/CLAUDE.md.ejs',
|
|
369
|
+
});
|
|
370
|
+
yield template.generate({
|
|
371
|
+
props: nextTemplateProps,
|
|
372
|
+
target: `${projectDir}/.claude/QUICKSTART.md`,
|
|
373
|
+
template: 'next-fullstack/.claude/QUICKSTART.md.ejs',
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
const claudeMdPath = `${projectDir}/CLAUDE.md`;
|
|
378
|
+
if (filesystem.exists(claudeMdPath)) {
|
|
379
|
+
const frontendName = frontend === 'nuxt' ? 'Nuxt 4' : 'Angular';
|
|
380
|
+
yield patching.update(claudeMdPath, (content) => content
|
|
381
|
+
.replace(/\{\{PROJECT_NAME\}\}/g, () => name)
|
|
382
|
+
.replace(/\{\{PROJECT_DIR\}\}/g, () => projectDir)
|
|
383
|
+
.replace(/\{\{API_MODE\}\}/g, () => apiMode)
|
|
384
|
+
.replace(/\{\{FRAMEWORK_MODE\}\}/g, () => frameworkMode)
|
|
385
|
+
.replace(/\{\{FRONTEND_FRAMEWORK\}\}/g, () => frontendName));
|
|
386
|
+
}
|
|
346
387
|
}
|
|
347
388
|
// Always initialize git
|
|
348
389
|
try {
|
|
@@ -420,6 +461,7 @@ const NewCommand = {
|
|
|
420
461
|
apiMode,
|
|
421
462
|
branch: apiBranch,
|
|
422
463
|
copyPath: apiCopy,
|
|
464
|
+
experimental,
|
|
423
465
|
frameworkMode,
|
|
424
466
|
frameworkUpstreamBranch,
|
|
425
467
|
linkPath: apiLink,
|
|
@@ -466,15 +508,20 @@ const NewCommand = {
|
|
|
466
508
|
// instead.` and silently disables CVE overrides.
|
|
467
509
|
(0, hoist_workspace_pnpm_config_1.hoistWorkspacePnpmConfig)({ filesystem, projectDir, subProjects: ['projects/api', 'projects/app'] });
|
|
468
510
|
// Install all packages
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
511
|
+
if (!experimental) {
|
|
512
|
+
const installSpinner = spin('Install all packages');
|
|
513
|
+
try {
|
|
514
|
+
const detectedPm = toolbox.pm.detect(projectDir);
|
|
515
|
+
yield system.run(`cd ${projectDir} && ${toolbox.pm.install(detectedPm)} && ${toolbox.pm.run('init', detectedPm)}`);
|
|
516
|
+
installSpinner.succeed('Successfully installed all packages');
|
|
517
|
+
}
|
|
518
|
+
catch (err) {
|
|
519
|
+
installSpinner.fail(`Failed to install packages: ${err.message}`);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
474
522
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
return;
|
|
523
|
+
else {
|
|
524
|
+
info('Skipping workspace install — run `bun install` (api) and `pnpm install` (app) manually.');
|
|
478
525
|
}
|
|
479
526
|
// Post-install format pass. processApiMode (run earlier in
|
|
480
527
|
// setupServerForFullstack) and convertAppCloneToVendored rewrite
|
|
@@ -482,10 +529,10 @@ const NewCommand = {
|
|
|
482
529
|
// `pnpm run format:check` (multi-line arrays/imports after region
|
|
483
530
|
// stripping, import-path rewrites that now fit single-line). The
|
|
484
531
|
// formatter is only available after install, so we normalize here.
|
|
485
|
-
if (apiMode && filesystem.isDirectory(`${projectDir}/projects/api`)) {
|
|
532
|
+
if (!experimental && apiMode && filesystem.isDirectory(`${projectDir}/projects/api`)) {
|
|
486
533
|
yield toolbox.apiMode.formatProject(`${projectDir}/projects/api`);
|
|
487
534
|
}
|
|
488
|
-
if (isNuxt && filesystem.isDirectory(`${projectDir}/projects/app`)) {
|
|
535
|
+
if (!experimental && isNuxt && filesystem.isDirectory(`${projectDir}/projects/app`)) {
|
|
489
536
|
yield toolbox.apiMode.formatProject(`${projectDir}/projects/app`);
|
|
490
537
|
}
|
|
491
538
|
// Create initial commit after everything is set up
|
|
@@ -511,9 +558,18 @@ const NewCommand = {
|
|
|
511
558
|
success(`Generated fullstack workspace with ${frontend} in ${projectDir} with ${name} app in ${helper.msToMinutesAndSeconds(timer())}m.`);
|
|
512
559
|
info('');
|
|
513
560
|
info('Next:');
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
561
|
+
if (experimental) {
|
|
562
|
+
info(` $ cd ${projectDir}`);
|
|
563
|
+
info(' Frontend: cd projects/app && pnpm install');
|
|
564
|
+
info(' API: cd projects/api && bun install');
|
|
565
|
+
info(' Configure projects/api/.env (see .env.example)');
|
|
566
|
+
info(' Start Postgres + run prisma generate / migrate');
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
info(` Run ${name}`);
|
|
570
|
+
info(` $ cd ${projectDir}`);
|
|
571
|
+
info(` $ ${toolbox.pm.run('start')}`);
|
|
572
|
+
}
|
|
517
573
|
info('');
|
|
518
574
|
if (!toolbox.parameters.options.fromGluegunMenu) {
|
|
519
575
|
process.exit();
|
|
@@ -42,6 +42,13 @@ const NewCommand = {
|
|
|
42
42
|
{ description: 'Git branch to clone from', flag: '--branch', required: false, type: 'string' },
|
|
43
43
|
{ description: 'Copy from local path instead of cloning', flag: '--copy', required: false, type: 'string' },
|
|
44
44
|
{ description: 'Symlink to local path instead of cloning', flag: '--link', required: false, type: 'string' },
|
|
45
|
+
{
|
|
46
|
+
default: false,
|
|
47
|
+
description: 'Use experimental nest-base template (Bun + Prisma + Postgres)',
|
|
48
|
+
flag: '--next',
|
|
49
|
+
required: false,
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
},
|
|
45
52
|
{
|
|
46
53
|
default: false,
|
|
47
54
|
description: 'Skip all interactive prompts',
|
|
@@ -77,6 +84,7 @@ const NewCommand = {
|
|
|
77
84
|
const cliApiMode = parameters.options['api-mode'] || parameters.options.apiMode;
|
|
78
85
|
const cliFrameworkMode = parameters.options['framework-mode'];
|
|
79
86
|
const cliFrameworkUpstreamBranch = parameters.options['framework-upstream-branch'];
|
|
87
|
+
const experimental = parameters.options.next === true || parameters.options.next === 'true';
|
|
80
88
|
// Determine noConfirm with priority: CLI > config > global > default (false)
|
|
81
89
|
const noConfirm = config.getNoConfirm({
|
|
82
90
|
cliValue: cliNoConfirm,
|
|
@@ -88,7 +96,7 @@ const NewCommand = {
|
|
|
88
96
|
// Info
|
|
89
97
|
info('Create a new server');
|
|
90
98
|
// Hint for non-interactive callers (e.g. Claude Code)
|
|
91
|
-
toolbox.tools.nonInteractiveHint('lt server create --name <name> --api-mode <Rest|GraphQL|Both> --noConfirm');
|
|
99
|
+
toolbox.tools.nonInteractiveHint('lt server create --name <name> --api-mode <Rest|GraphQL|Both> [--next] --noConfirm');
|
|
92
100
|
// Check git
|
|
93
101
|
if (!(yield git.gitInstalled())) {
|
|
94
102
|
return;
|
|
@@ -150,7 +158,11 @@ const NewCommand = {
|
|
|
150
158
|
}
|
|
151
159
|
// Determine API mode with priority: CLI > config > global > interactive (default: Rest)
|
|
152
160
|
let apiMode;
|
|
153
|
-
if (
|
|
161
|
+
if (experimental) {
|
|
162
|
+
apiMode = 'Rest';
|
|
163
|
+
info('Using experimental nest-base template (Bun + Prisma + Postgres + Better-Auth)');
|
|
164
|
+
}
|
|
165
|
+
else if (cliApiMode) {
|
|
154
166
|
apiMode = cliApiMode;
|
|
155
167
|
}
|
|
156
168
|
else if (configApiMode) {
|
|
@@ -184,7 +196,10 @@ const NewCommand = {
|
|
|
184
196
|
// Determine framework consumption mode — same resolution cascade as
|
|
185
197
|
// lt fullstack init: CLI flag > lt.config > interactive (default npm).
|
|
186
198
|
let frameworkMode;
|
|
187
|
-
if (
|
|
199
|
+
if (experimental) {
|
|
200
|
+
frameworkMode = 'npm';
|
|
201
|
+
}
|
|
202
|
+
else if (cliFrameworkMode === 'npm' || cliFrameworkMode === 'vendor') {
|
|
188
203
|
frameworkMode = cliFrameworkMode;
|
|
189
204
|
}
|
|
190
205
|
else if (cliFrameworkMode) {
|
|
@@ -222,6 +237,7 @@ const NewCommand = {
|
|
|
222
237
|
branch,
|
|
223
238
|
copyPath,
|
|
224
239
|
description,
|
|
240
|
+
experimental,
|
|
225
241
|
frameworkMode,
|
|
226
242
|
frameworkUpstreamBranch,
|
|
227
243
|
linkPath,
|
|
@@ -279,36 +295,47 @@ const NewCommand = {
|
|
|
279
295
|
}
|
|
280
296
|
// Derive controller type from API mode and save project config
|
|
281
297
|
const controllerType = apiMode;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
298
|
+
if (!experimental) {
|
|
299
|
+
// Create lt.config.json
|
|
300
|
+
const projectConfig = {
|
|
301
|
+
commands: {
|
|
302
|
+
server: {
|
|
303
|
+
module: {
|
|
304
|
+
controller: controllerType,
|
|
305
|
+
},
|
|
288
306
|
},
|
|
289
307
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
308
|
+
meta: {
|
|
309
|
+
apiMode,
|
|
310
|
+
version: '1.0.0',
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
const configPath = filesystem.path(projectDir, 'lt.config.json');
|
|
314
|
+
filesystem.write(configPath, projectConfig, { jsonIndent: 2 });
|
|
315
|
+
info('');
|
|
316
|
+
success(`Configuration saved to ${projectDir}/lt.config.json`);
|
|
317
|
+
info(` API mode: ${apiMode}`);
|
|
318
|
+
info(` Default controller type: ${controllerType}`);
|
|
319
|
+
}
|
|
302
320
|
// We're done, so show what to do next
|
|
303
321
|
info('');
|
|
304
322
|
success(`Generated ${name} server with lenne.Tech CLI ${meta.version()} in ${helper.msToMinutesAndSeconds(timer())}m.`);
|
|
305
323
|
info('');
|
|
306
324
|
info('Next:');
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
325
|
+
if (experimental) {
|
|
326
|
+
info(` Go to project directory: cd ${projectDir}`);
|
|
327
|
+
info(' Install dependencies: bun install');
|
|
328
|
+
info(' Configure .env (see .env.example)');
|
|
329
|
+
info(' Start Postgres + run prisma generate / migrate');
|
|
330
|
+
info(' Start server: bun run dev');
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
info(' Start database server (e.g. MongoDB)');
|
|
334
|
+
info(` Check config: ${projectDir}/src/config.env.ts`);
|
|
335
|
+
info(` Go to project directory: cd ${projectDir}`);
|
|
336
|
+
info(` Run tests: ${toolbox.pm.run('test:e2e')}`);
|
|
337
|
+
info(` Start server: ${toolbox.pm.run('start')}`);
|
|
338
|
+
}
|
|
312
339
|
info('');
|
|
313
340
|
if (!toolbox.parameters.options.fromGluegunMenu) {
|
|
314
341
|
process.exit();
|
|
@@ -633,13 +633,16 @@ class Server {
|
|
|
633
633
|
setupServer(dest, options) {
|
|
634
634
|
return __awaiter(this, void 0, void 0, function* () {
|
|
635
635
|
const { apiMode: apiModeHelper, patching, system, template, templateHelper } = this.toolbox;
|
|
636
|
-
const { apiMode, author = '', branch, copyPath, description = '', frameworkMode = 'npm', frameworkUpstreamBranch, linkPath, name, projectDir, skipInstall = false, skipPatching = false, } = options;
|
|
636
|
+
const { apiMode, author = '', branch, copyPath, description = '', experimental = false, frameworkMode = 'npm', frameworkUpstreamBranch, linkPath, name, projectDir, skipInstall = false, skipPatching = false, } = options;
|
|
637
|
+
const repoUrl = experimental
|
|
638
|
+
? 'https://github.com/lenneTech/nest-base.git'
|
|
639
|
+
: 'https://github.com/lenneTech/nest-server-starter.git';
|
|
637
640
|
// Setup template
|
|
638
641
|
const result = yield templateHelper.setup(dest, {
|
|
639
642
|
branch,
|
|
640
643
|
copyPath,
|
|
641
644
|
linkPath,
|
|
642
|
-
repoUrl
|
|
645
|
+
repoUrl,
|
|
643
646
|
});
|
|
644
647
|
if (!result.success) {
|
|
645
648
|
return { method: result.method, path: result.path, success: false };
|
|
@@ -651,18 +654,20 @@ class Server {
|
|
|
651
654
|
// Apply patches (config.env.ts, package.json, main.ts, meta.json)
|
|
652
655
|
if (!skipPatching) {
|
|
653
656
|
try {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
.
|
|
665
|
-
|
|
657
|
+
if (!experimental) {
|
|
658
|
+
// Generate README
|
|
659
|
+
yield template.generate({
|
|
660
|
+
props: { description, name },
|
|
661
|
+
target: `${dest}/README.md`,
|
|
662
|
+
template: 'nest-server-starter/README.md.ejs',
|
|
663
|
+
});
|
|
664
|
+
// Replace secret or private keys and update database names via AST
|
|
665
|
+
this.patchConfigEnvTs(`${dest}/src/config.env.ts`, projectDir);
|
|
666
|
+
// Update Swagger configuration in main.ts
|
|
667
|
+
yield patching.update(`${dest}/src/main.ts`, (content) => content
|
|
668
|
+
.replace(/\.setTitle\('.*?'\)/, `.setTitle('${name}')`)
|
|
669
|
+
.replace(/\.setDescription\('.*?'\)/, `.setDescription('${description || name}')`));
|
|
670
|
+
}
|
|
666
671
|
// Update package.json
|
|
667
672
|
yield patching.update(`${dest}/package.json`, (config) => {
|
|
668
673
|
config.author = author;
|
|
@@ -674,13 +679,15 @@ class Server {
|
|
|
674
679
|
config.version = '0.0.1';
|
|
675
680
|
return config;
|
|
676
681
|
});
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
682
|
+
if (!experimental) {
|
|
683
|
+
// Update meta.json if exists
|
|
684
|
+
if (this.filesystem.exists(`${dest}/src/meta`)) {
|
|
685
|
+
yield patching.update(`${dest}/src/meta`, (config) => {
|
|
686
|
+
config.name = name;
|
|
687
|
+
config.description = description;
|
|
688
|
+
return config;
|
|
689
|
+
});
|
|
690
|
+
}
|
|
684
691
|
}
|
|
685
692
|
}
|
|
686
693
|
catch (err) {
|
|
@@ -703,7 +710,7 @@ class Server {
|
|
|
703
710
|
// manifest (same dance as in setupServerForFullstack).
|
|
704
711
|
let standaloneVendorUpstreamDeps = {};
|
|
705
712
|
let standaloneVendorCoreEssentials = [];
|
|
706
|
-
if (frameworkMode === 'vendor') {
|
|
713
|
+
if (!experimental && frameworkMode === 'vendor') {
|
|
707
714
|
try {
|
|
708
715
|
const converted = yield this.convertCloneToVendored({
|
|
709
716
|
dest,
|
|
@@ -718,7 +725,7 @@ class Server {
|
|
|
718
725
|
standaloneVendorCoreEssentials = this.readApiModeGraphqlEssentials(dest);
|
|
719
726
|
}
|
|
720
727
|
// Process API mode (before install so package.json is correct)
|
|
721
|
-
if (apiMode) {
|
|
728
|
+
if (!experimental && apiMode) {
|
|
722
729
|
try {
|
|
723
730
|
yield apiModeHelper.processApiMode(dest, apiMode);
|
|
724
731
|
}
|
|
@@ -727,7 +734,7 @@ class Server {
|
|
|
727
734
|
}
|
|
728
735
|
}
|
|
729
736
|
// Restore core essentials after processApiMode stripped them (vendor + REST only).
|
|
730
|
-
if (frameworkMode === 'vendor' && apiMode === 'Rest') {
|
|
737
|
+
if (!experimental && frameworkMode === 'vendor' && apiMode === 'Rest') {
|
|
731
738
|
try {
|
|
732
739
|
this.restoreVendorCoreEssentials({
|
|
733
740
|
dest,
|
|
@@ -740,9 +747,11 @@ class Server {
|
|
|
740
747
|
}
|
|
741
748
|
}
|
|
742
749
|
// Patch CLAUDE.md with API mode info
|
|
743
|
-
|
|
750
|
+
if (!experimental) {
|
|
751
|
+
this.patchClaudeMdApiMode(dest, apiMode);
|
|
752
|
+
}
|
|
744
753
|
// Install packages
|
|
745
|
-
if (!skipInstall) {
|
|
754
|
+
if (!skipInstall && !experimental) {
|
|
746
755
|
try {
|
|
747
756
|
const { pm } = this.toolbox;
|
|
748
757
|
yield system.run(`cd "${dest}" && ${pm.install(pm.detect(dest))}`);
|
|
@@ -771,7 +780,10 @@ class Server {
|
|
|
771
780
|
setupServerForFullstack(dest, options) {
|
|
772
781
|
return __awaiter(this, void 0, void 0, function* () {
|
|
773
782
|
const { apiMode: apiModeHelper, templateHelper } = this.toolbox;
|
|
774
|
-
const { apiMode, branch, copyPath, frameworkMode = 'npm', frameworkUpstreamBranch, linkPath, name, projectDir, } = options;
|
|
783
|
+
const { apiMode, branch, copyPath, experimental = false, frameworkMode = 'npm', frameworkUpstreamBranch, linkPath, name, projectDir, } = options;
|
|
784
|
+
const repoUrl = experimental
|
|
785
|
+
? 'https://github.com/lenneTech/nest-base.git'
|
|
786
|
+
: 'https://github.com/lenneTech/nest-server-starter';
|
|
775
787
|
// Both npm and vendor mode clone nest-server-starter as the base. The
|
|
776
788
|
// starter ships the minimal consumer conventions a project needs
|
|
777
789
|
// (src/server/common/models/persistence.model.ts, src/server/modules/user/,
|
|
@@ -791,7 +803,7 @@ class Server {
|
|
|
791
803
|
branch,
|
|
792
804
|
copyPath,
|
|
793
805
|
linkPath,
|
|
794
|
-
repoUrl
|
|
806
|
+
repoUrl,
|
|
795
807
|
});
|
|
796
808
|
if (!result.success) {
|
|
797
809
|
return { method: result.method, path: result.path, success: false };
|
|
@@ -801,18 +813,33 @@ class Server {
|
|
|
801
813
|
return { method: 'link', path: result.path, success: true };
|
|
802
814
|
}
|
|
803
815
|
// Apply minimal patches for fullstack
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
816
|
+
if (!experimental) {
|
|
817
|
+
try {
|
|
818
|
+
// Write meta.json
|
|
819
|
+
this.filesystem.write(`${dest}/src/meta.json`, {
|
|
820
|
+
description: `API for ${name} app`,
|
|
821
|
+
name: `${name}-api-server`,
|
|
822
|
+
version: '0.0.0',
|
|
823
|
+
});
|
|
824
|
+
// Replace secret or private keys and update database names via AST
|
|
825
|
+
this.patchConfigEnvTs(`${dest}/src/config.env.ts`, projectDir);
|
|
826
|
+
}
|
|
827
|
+
catch (err) {
|
|
828
|
+
return { method: result.method, path: dest, success: false };
|
|
829
|
+
}
|
|
813
830
|
}
|
|
814
|
-
|
|
815
|
-
|
|
831
|
+
else {
|
|
832
|
+
try {
|
|
833
|
+
yield this.toolbox.patching.update(`${dest}/package.json`, (config) => {
|
|
834
|
+
config.name = projectDir;
|
|
835
|
+
config.description = `API for ${name} app`;
|
|
836
|
+
config.version = '0.0.0';
|
|
837
|
+
return config;
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
catch (err) {
|
|
841
|
+
return { method: result.method, path: dest, success: false };
|
|
842
|
+
}
|
|
816
843
|
}
|
|
817
844
|
// Clean up copied template artifacts
|
|
818
845
|
if (result.method === 'copy') {
|
|
@@ -833,7 +860,7 @@ class Server {
|
|
|
833
860
|
// without hard-coding package lists.
|
|
834
861
|
let vendorUpstreamDeps = {};
|
|
835
862
|
let vendorCoreEssentials = [];
|
|
836
|
-
if (frameworkMode === 'vendor') {
|
|
863
|
+
if (!experimental && frameworkMode === 'vendor') {
|
|
837
864
|
try {
|
|
838
865
|
const converted = yield this.convertCloneToVendored({
|
|
839
866
|
dest,
|
|
@@ -856,7 +883,7 @@ class Server {
|
|
|
856
883
|
vendorCoreEssentials = this.readApiModeGraphqlEssentials(dest);
|
|
857
884
|
}
|
|
858
885
|
// Process API mode (before install which happens at monorepo level)
|
|
859
|
-
if (apiMode) {
|
|
886
|
+
if (!experimental && apiMode) {
|
|
860
887
|
try {
|
|
861
888
|
yield apiModeHelper.processApiMode(dest, apiMode);
|
|
862
889
|
}
|
|
@@ -867,7 +894,7 @@ class Server {
|
|
|
867
894
|
// In vendor mode + REST, re-add the graphql essentials that
|
|
868
895
|
// processApiMode just stripped. Both and GraphQL keep all packages
|
|
869
896
|
// by construction and don't need restoration.
|
|
870
|
-
if (frameworkMode === 'vendor' && apiMode === 'Rest') {
|
|
897
|
+
if (!experimental && frameworkMode === 'vendor' && apiMode === 'Rest') {
|
|
871
898
|
try {
|
|
872
899
|
this.restoreVendorCoreEssentials({
|
|
873
900
|
dest,
|
|
@@ -881,7 +908,9 @@ class Server {
|
|
|
881
908
|
}
|
|
882
909
|
}
|
|
883
910
|
// Patch CLAUDE.md with API mode info
|
|
884
|
-
|
|
911
|
+
if (!experimental) {
|
|
912
|
+
this.patchClaudeMdApiMode(dest, apiMode);
|
|
913
|
+
}
|
|
885
914
|
return { method: result.method, path: dest, success: true };
|
|
886
915
|
});
|
|
887
916
|
}
|
|
@@ -43,14 +43,25 @@ class Tools {
|
|
|
43
43
|
* Suggests using CLI parameters instead of interactive prompts.
|
|
44
44
|
* Only shows once per session.
|
|
45
45
|
*
|
|
46
|
+
* Skipped when the caller already passed `--noConfirm` — they're
|
|
47
|
+
* deliberately running headless and don't need a hint to repeat the
|
|
48
|
+
* command, which would just be confusing noise (the friction-log
|
|
49
|
+
* complaint that triggered this guard).
|
|
50
|
+
*
|
|
46
51
|
* @param usage - Example command with parameters, e.g. "lt fullstack init --name <name> --frontend <nuxt|angular> --noConfirm"
|
|
47
52
|
*/
|
|
48
53
|
nonInteractiveHint(usage) {
|
|
54
|
+
var _a;
|
|
49
55
|
if (this.hintShown || process.stdin.isTTY) {
|
|
50
56
|
return;
|
|
51
57
|
}
|
|
58
|
+
const { parameters, print } = this.toolbox;
|
|
59
|
+
const noConfirm = (_a = parameters === null || parameters === void 0 ? void 0 : parameters.options) === null || _a === void 0 ? void 0 : _a.noConfirm;
|
|
60
|
+
if (noConfirm === true || noConfirm === 'true') {
|
|
61
|
+
this.hintShown = true;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
52
64
|
this.hintShown = true;
|
|
53
|
-
const { print } = this.toolbox;
|
|
54
65
|
print.info(print.colors.yellow(`Hint: Non-interactive mode detected. Use parameters to skip prompts:`));
|
|
55
66
|
print.info(print.colors.yellow(` ${usage}`));
|
|
56
67
|
print.info('');
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# QUICKSTART — `<%= props.name %>` workspace
|
|
2
|
+
|
|
3
|
+
A fresh AI agent that just opened this workspace. Read this once, then
|
|
4
|
+
switch to a subproject.
|
|
5
|
+
|
|
6
|
+
## You almost certainly want a subproject
|
|
7
|
+
|
|
8
|
+
| If you are doing | Go to |
|
|
9
|
+
| --------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
10
|
+
| Backend / API / DB / Prisma / auth / permissions | `cd projects/api` → [`projects/api/.claude/QUICKSTART.md`](../projects/api/.claude/QUICKSTART.md) |
|
|
11
|
+
| Frontend / Nuxt / pages / components | `cd projects/app` → its `README.md` and `CLAUDE.md` |
|
|
12
|
+
| Cross-project work (deploy, CI, monorepo tooling) | this root level |
|
|
13
|
+
|
|
14
|
+
The moment you're touching domain code or framework conventions, you
|
|
15
|
+
belong in a subproject. This root level is just the workspace shell.
|
|
16
|
+
|
|
17
|
+
## Bring up the dev environment
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# API
|
|
21
|
+
cd projects/api
|
|
22
|
+
bun install
|
|
23
|
+
bun run setup # generates .env with strong random secrets
|
|
24
|
+
docker compose up -d postgres
|
|
25
|
+
bun run prepare:schema # only needed before first migrate / when feature flags change
|
|
26
|
+
bun run prisma:generate
|
|
27
|
+
bun run prisma:migrate
|
|
28
|
+
bun run dev # boots Postgres if needed, opens the Dev Hub at /dev
|
|
29
|
+
|
|
30
|
+
# Frontend (in another shell)
|
|
31
|
+
cd projects/app
|
|
32
|
+
pnpm install
|
|
33
|
+
pnpm dev
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If `bun run prisma:migrate` fails with a P1000 auth error after
|
|
37
|
+
re-running `bun run setup`, the Postgres volume still holds the old
|
|
38
|
+
password — run `docker compose down -v && docker compose up -d
|
|
39
|
+
postgres` to wipe it, then migrate again.
|
|
40
|
+
|
|
41
|
+
## Stack
|
|
42
|
+
|
|
43
|
+
| | API | App |
|
|
44
|
+
| -------- | ------------------ | ------------------ |
|
|
45
|
+
| Runtime | Bun 1.x | Node 22 |
|
|
46
|
+
| Framework| NestJS 11 | Nuxt 4 |
|
|
47
|
+
| Database | Postgres 18 | — |
|
|
48
|
+
| ORM | Prisma 7 | — |
|
|
49
|
+
| Auth | Better-Auth | — |
|
|
50
|
+
| Lang | TypeScript strict | TypeScript strict |
|
|
51
|
+
|
|
52
|
+
For everything else (architecture, conventions, gates, debugging),
|
|
53
|
+
switch to the subproject.
|
|
54
|
+
|
|
55
|
+
## Don'ts
|
|
56
|
+
|
|
57
|
+
- Don't add repo conventions in this root — they belong in the
|
|
58
|
+
subproject they apply to.
|
|
59
|
+
- Don't introduce GraphQL / MongoDB / Mongoose / vendor-mode
|
|
60
|
+
framework cores. Those are explicitly out of scope for `--next`
|
|
61
|
+
workspaces; see the API's `docs/architecture.md` for context.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# CLAUDE.md — `<%= props.name %>` workspace
|
|
2
|
+
|
|
3
|
+
This is a fullstack workspace with separate Claude Code contexts per
|
|
4
|
+
subproject. Pick the right one for your task and read its `CLAUDE.md`
|
|
5
|
+
first — that's where the conventions, architecture, and quickstart
|
|
6
|
+
live.
|
|
7
|
+
|
|
8
|
+
## Routing
|
|
9
|
+
|
|
10
|
+
| Task | Where to read |
|
|
11
|
+
| ---------------------------------------------- | ------------------------------------------------------------------- |
|
|
12
|
+
| Backend / API / database / Prisma migrations | [`projects/api/CLAUDE.md`](./projects/api/CLAUDE.md) |
|
|
13
|
+
| Frontend / Nuxt / pages / components | [`projects/app/CLAUDE.md`](./projects/app/CLAUDE.md) |
|
|
14
|
+
| 60-second agent onboarding | [`.claude/QUICKSTART.md`](./.claude/QUICKSTART.md) |
|
|
15
|
+
|
|
16
|
+
## Tech stack at a glance
|
|
17
|
+
|
|
18
|
+
- **API** — Bun 1.x · NestJS 11 · Prisma 7 · Postgres 18 · Better-Auth · REST + OpenAPI 3.1
|
|
19
|
+
- **App** — Nuxt 4 · Vue 3 · TypeScript
|
|
20
|
+
|
|
21
|
+
Detailed conventions live in the subproject `CLAUDE.md` files. Don't
|
|
22
|
+
add convention rules to this root file — they belong in the subproject
|
|
23
|
+
they apply to.
|
|
24
|
+
|
|
25
|
+
## Out of scope (do not add to either subproject)
|
|
26
|
+
|
|
27
|
+
- GraphQL / Apollo
|
|
28
|
+
- Mongoose / MongoDB
|
|
29
|
+
- Vendor mode for the framework core (the `--next` template ships
|
|
30
|
+
`nest-base` directly, no `@lenne.tech/nest-server` npm dependency)
|
|
31
|
+
- The legacy `@Restricted` / `@Roles` decorators
|
|
32
|
+
|
|
33
|
+
These are explicitly removed in the `nest-base` template and a real
|
|
34
|
+
project should never reintroduce them. See
|
|
35
|
+
[`projects/api/docs/architecture.md`](./projects/api/docs/architecture.md)
|
|
36
|
+
"Out of scope" for the rationale.
|
|
37
|
+
|
|
38
|
+
## When you open this repo cold
|
|
39
|
+
|
|
40
|
+
1. Identify whether the task is backend, frontend, or cross-project.
|
|
41
|
+
2. `cd projects/api` (or `projects/app`) and read its `CLAUDE.md`.
|
|
42
|
+
3. Run the subproject's quality gates before committing.
|
|
43
|
+
4. Cross-project changes (Docker compose, repo hygiene, deploy config)
|
|
44
|
+
stay at this root and follow each subproject's conventions when they
|
|
45
|
+
touch its files.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# <%= props.name %>
|
|
2
|
+
|
|
3
|
+
Fullstack workspace generated by `lt fullstack init --next`. The API is
|
|
4
|
+
the next-generation [`nest-base`](https://github.com/lenneTech/nest-base)
|
|
5
|
+
template (Bun + Prisma + Postgres + Better-Auth + REST). The app is a
|
|
6
|
+
Nuxt 4 frontend.
|
|
7
|
+
|
|
8
|
+
This root README intentionally stays minimal — each subproject has its
|
|
9
|
+
own `README.md` / `CLAUDE.md` / `.claude/` with the detail you actually
|
|
10
|
+
need while working in it.
|
|
11
|
+
|
|
12
|
+
## Layout
|
|
13
|
+
|
|
14
|
+
- [`projects/api/`](./projects/api/) — NestJS backend (Bun · Prisma 7 · Postgres 18 · Better-Auth)
|
|
15
|
+
- [`projects/app/`](./projects/app/) — Nuxt 4 frontend
|
|
16
|
+
- [`.claude/QUICKSTART.md`](./.claude/QUICKSTART.md) — agent routing card
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
### API (Bun + Prisma + Postgres)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cd projects/api
|
|
24
|
+
bun install
|
|
25
|
+
bun run setup # generate .env with strong random secrets
|
|
26
|
+
docker compose up -d postgres
|
|
27
|
+
bun run prepare:schema # concatenate active feature schemas
|
|
28
|
+
bun run prisma:generate
|
|
29
|
+
bun run prisma:migrate
|
|
30
|
+
bun run dev # boots Postgres if needed, opens the Dev Hub
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The Dev Hub is at `http://localhost:3000/dev`. See
|
|
34
|
+
[`projects/api/README.md`](./projects/api/README.md) for the full tour.
|
|
35
|
+
|
|
36
|
+
### Frontend (Nuxt 4)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd projects/app
|
|
40
|
+
pnpm install
|
|
41
|
+
pnpm dev
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
See [`projects/app/README.md`](./projects/app/README.md).
|
|
45
|
+
|
|
46
|
+
## License
|
|
47
|
+
|
|
48
|
+
MIT
|
|
@@ -117,6 +117,7 @@ Flags:
|
|
|
117
117
|
- `--frontend-framework-mode npm|vendor` — Frontend mode
|
|
118
118
|
- `--framework-upstream-branch <tag>` — Specific nest-server version for vendor
|
|
119
119
|
- `--dry-run` — Show plan without making changes
|
|
120
|
+
- `--next` — **Experimental:** clone [`nest-base`](https://github.com/lenneTech/nest-base) (Bun + Prisma 7 + Postgres + Better-Auth) for the API instead of `nest-server-starter`. Forces `--api-mode Rest`, `--framework-mode npm`, and skips workspace install (run `pnpm install` for app and `bun install` for api manually). Downstream `lt server module/object/addProp/test/permissions` are NOT compatible with the resulting layout.
|
|
120
121
|
|
|
121
122
|
---
|
|
122
123
|
|
package/docs/commands.md
CHANGED
|
@@ -79,13 +79,16 @@ lt server create [name] [options]
|
|
|
79
79
|
|--------|-------------|
|
|
80
80
|
| `--description <text>` | Project description |
|
|
81
81
|
| `--author <name>` | Author name |
|
|
82
|
+
| `--api-mode <Rest\|GraphQL\|Both>` | API mode (ignored with `--next`) |
|
|
83
|
+
| `--framework-mode <npm\|vendor>` | Framework consumption mode (ignored with `--next`) |
|
|
82
84
|
| `--branch <branch>` / `-b` | Branch of nest-server-starter to use as template |
|
|
83
85
|
| `--copy <path>` / `-c` | Copy from local template directory instead of cloning |
|
|
84
86
|
| `--link <path>` | Symlink to local template directory (fastest, changes affect original) |
|
|
85
87
|
| `--git` | Initialize git repository |
|
|
88
|
+
| `--next` | **Experimental:** clone [`nest-base`](https://github.com/lenneTech/nest-base) (Bun + Prisma 7 + Postgres + Better-Auth) instead of `nest-server-starter`. Skips API-mode / vendor-mode / install / lt.config.json processing. |
|
|
86
89
|
| `--noConfirm` | Skip confirmation prompts |
|
|
87
90
|
|
|
88
|
-
**CLAUDE.md Patching:** If the project contains a `CLAUDE.md`, the generic API mode description is replaced with the selected mode. In single-mode projects (`Rest` or `GraphQL`), the "API Mode System" documentation section is condensed to a brief note.
|
|
91
|
+
**CLAUDE.md Patching:** If the project contains a `CLAUDE.md`, the generic API mode description is replaced with the selected mode. In single-mode projects (`Rest` or `GraphQL`), the "API Mode System" documentation section is condensed to a brief note. Skipped when `--next` is used.
|
|
89
92
|
|
|
90
93
|
**Configuration:** `commands.server.create.*`, `defaults.author`, `defaults.noConfirm`
|
|
91
94
|
|
|
@@ -532,6 +535,7 @@ lt fullstack init [options]
|
|
|
532
535
|
| `--framework-mode <mode>` | Backend framework consumption mode: `npm` (classic) or `vendor` (pilot, core copied to `src/core/`) |
|
|
533
536
|
| `--framework-upstream-branch <ref>` | Upstream `nest-server` branch/tag to vendor from (only with `--framework-mode vendor`) |
|
|
534
537
|
| `--frontend-framework-mode <mode>` | Frontend framework consumption mode: `npm` or `vendor` (nuxt-extensions copied to `app/core/`) |
|
|
538
|
+
| `--next` | **Experimental:** clone [`nest-base`](https://github.com/lenneTech/nest-base) (Bun + Prisma 7 + Postgres + Better-Auth) for the API instead of `nest-server-starter`. Forces `--api-mode Rest` and `--framework-mode npm`, skips workspace install (run `pnpm install` for app and `bun install` for api manually). |
|
|
535
539
|
| `--dry-run` | Print the resolved plan without making any changes |
|
|
536
540
|
| `--git` | Push initial commit to remote repository (git is always initialized) |
|
|
537
541
|
| `--git-link <url>` | Git remote repository URL (required when `--git` is true) |
|