@lenne.tech/cli 1.14.0 → 1.16.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.
@@ -21,7 +21,7 @@ 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
@@ -344,16 +344,46 @@ const NewCommand = {
344
344
  const ngBaseSpinner = spin(`Integrate example for ${frontend}`);
345
345
  // Remove git folder after clone
346
346
  filesystem.remove(`${projectDir}/.git`);
347
- // Patch CLAUDE.md with project-specific values
348
- const claudeMdPath = `${projectDir}/CLAUDE.md`;
349
- if (filesystem.exists(claudeMdPath)) {
350
- const frontendName = frontend === 'nuxt' ? 'Nuxt 4' : 'Angular';
351
- yield patching.update(claudeMdPath, (content) => content
352
- .replace(/\{\{PROJECT_NAME\}\}/g, () => name)
353
- .replace(/\{\{PROJECT_DIR\}\}/g, () => projectDir)
354
- .replace(/\{\{API_MODE\}\}/g, () => apiMode)
355
- .replace(/\{\{FRAMEWORK_MODE\}\}/g, () => frameworkMode)
356
- .replace(/\{\{FRONTEND_FRAMEWORK\}\}/g, () => frontendName));
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
+ }
357
387
  }
358
388
  // Always initialize git
359
389
  try {
@@ -442,6 +472,39 @@ const NewCommand = {
442
472
  serverSpinner.fail(`Failed to set up API: ${apiResult.path}`);
443
473
  return;
444
474
  }
475
+ // Auto-run `bun run rename <projectDir>` for the experimental nest-base
476
+ // template. The template ships with hard-coded `nest-base` references in
477
+ // four files (package.json, README.md, portless.yml, docker-compose.yml).
478
+ // The rename script patches all four idempotently. Since the consumer
479
+ // already gave us --name, doing this for them is strictly less
480
+ // friction-prone than relying on a manual follow-up step (which agents
481
+ // and humans both forget). Failure is non-fatal: the workspace is still
482
+ // usable, the user can re-run `bun run rename <name>` manually.
483
+ //
484
+ // Note: setupServerForFullstack already patched projects/api/package.json
485
+ // to set `name = projectDir`. The rename planner reads that name as the
486
+ // "old" slug, which would short-circuit the README/portless/compose
487
+ // rewrites because they still say `nest-base`. We restore the canonical
488
+ // `name = "nest-base"` first so the planner has a coherent starting
489
+ // state across all four files; the rename then writes the project name
490
+ // into every spot consistently.
491
+ if (experimental && apiResult.method !== 'link') {
492
+ const apiPackageJsonPath = `${apiDest}/package.json`;
493
+ if (filesystem.exists(apiPackageJsonPath)) {
494
+ yield patching.update(apiPackageJsonPath, (config) => {
495
+ config.name = 'nest-base';
496
+ return config;
497
+ });
498
+ }
499
+ const renameSpinner = spin(`Rename nest-base → ${projectDir}`);
500
+ try {
501
+ yield system.run(`cd ${apiDest} && bun run rename ${projectDir}`);
502
+ renameSpinner.succeed(`Renamed nest-base → ${projectDir} in projects/api`);
503
+ }
504
+ catch (err) {
505
+ renameSpinner.warn(`Auto-rename failed (${err.message}). Run \`bun run rename ${projectDir}\` manually inside projects/api.`);
506
+ }
507
+ }
445
508
  // Create lt.config.json for API
446
509
  // Note: frameworkMode is persisted under meta so that subsequent `lt
447
510
  // server module` / `addProp` / `permissions` calls can detect the mode
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/cli",
3
- "version": "1.14.0",
3
+ "version": "1.16.0",
4
4
  "description": "lenne.Tech CLI: lt",
5
5
  "keywords": [
6
6
  "lenne.Tech",