@lenne.tech/cli 1.9.6 → 1.11.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 (38) hide show
  1. package/README.md +88 -3
  2. package/build/commands/config/validate.js +2 -0
  3. package/build/commands/frontend/convert-mode.js +198 -0
  4. package/build/commands/fullstack/convert-mode.js +368 -0
  5. package/build/commands/fullstack/init.js +150 -4
  6. package/build/commands/fullstack/update.js +177 -0
  7. package/build/commands/server/add-property.js +29 -2
  8. package/build/commands/server/convert-mode.js +197 -0
  9. package/build/commands/server/create.js +41 -3
  10. package/build/commands/server/module.js +58 -25
  11. package/build/commands/server/object.js +26 -5
  12. package/build/commands/server/permissions.js +20 -6
  13. package/build/commands/server/test.js +7 -1
  14. package/build/commands/status.js +94 -3
  15. package/build/config/vendor-frontend-runtime-deps.json +4 -0
  16. package/build/config/vendor-runtime-deps.json +9 -0
  17. package/build/extensions/api-mode.js +19 -3
  18. package/build/extensions/frontend-helper.js +652 -0
  19. package/build/extensions/server.js +1475 -3
  20. package/build/lib/framework-detection.js +167 -0
  21. package/build/lib/frontend-framework-detection.js +129 -0
  22. package/build/templates/nest-server-module/inputs/template-create.input.ts.ejs +1 -1
  23. package/build/templates/nest-server-module/inputs/template.input.ts.ejs +1 -1
  24. package/build/templates/nest-server-module/outputs/template-fac-result.output.ts.ejs +1 -1
  25. package/build/templates/nest-server-module/template.controller.ts.ejs +1 -1
  26. package/build/templates/nest-server-module/template.model.ts.ejs +1 -1
  27. package/build/templates/nest-server-module/template.module.ts.ejs +1 -1
  28. package/build/templates/nest-server-module/template.resolver.ts.ejs +1 -1
  29. package/build/templates/nest-server-module/template.service.ts.ejs +1 -1
  30. package/build/templates/nest-server-object/template-create.input.ts.ejs +1 -1
  31. package/build/templates/nest-server-object/template.input.ts.ejs +1 -1
  32. package/build/templates/nest-server-object/template.object.ts.ejs +1 -1
  33. package/build/templates/nest-server-tests/tests.e2e-spec.ts.ejs +1 -1
  34. package/docs/LT-ECOSYSTEM-GUIDE.md +973 -0
  35. package/docs/VENDOR-MODE-WORKFLOW.md +471 -0
  36. package/docs/commands.md +196 -0
  37. package/docs/lt.config.md +9 -7
  38. package/package.json +17 -8
package/README.md CHANGED
@@ -38,9 +38,11 @@ $ lt
38
38
 
39
39
  ## Documentation
40
40
 
41
- - [Command Reference](docs/commands.md) - Complete list of all commands with options
42
- - [Configuration Guide](docs/lt.config.md) - Configuration file documentation
43
- - [Plugin Guide](docs/plugins.md) - How to create plugins
41
+ - **[LT-ECOSYSTEM-GUIDE](docs/LT-ECOSYSTEM-GUIDE.md)** Complete reference for `lt` CLI **and** the `lt-dev` Claude-Code Plugin (architecture, functions, vendor-mode workflows, agents, skills)
42
+ - **[VENDOR-MODE-WORKFLOW](docs/VENDOR-MODE-WORKFLOW.md)** — Step-by-step guide for npm → vendor conversion, updates, and rollback
43
+ - [Command Reference](docs/commands.md) Complete list of all commands with options
44
+ - [Configuration Guide](docs/lt.config.md) — Configuration file documentation
45
+ - [Plugin Guide](docs/plugins.md) — How to create plugins
44
46
 
45
47
  ## Quick Start
46
48
 
@@ -55,6 +57,89 @@ $ lt status
55
57
  $ lt completion install
56
58
  ```
57
59
 
60
+ ## Framework consumption modes (nest-server)
61
+
62
+ When you create a new api project (`lt fullstack init` or `lt server create`),
63
+ the CLI supports two framework consumption modes:
64
+
65
+ **`npm` mode (default)** — `@lenne.tech/nest-server` is installed as an npm
66
+ dependency. Framework source lives in `node_modules/@lenne.tech/nest-server/`.
67
+ Imports use the bare specifier `from '@lenne.tech/nest-server'`. Update path:
68
+ `/lt-dev:backend:update-nest-server` (Claude Code agent).
69
+
70
+ **`vendor` mode** — The framework's `core/` directory is copied directly into
71
+ `<api>/src/core/` as first-class project code. No `@lenne.tech/nest-server`
72
+ npm dependency. Generated imports use relative paths (`from '../../../core'`).
73
+ Local patches are allowed and tracked in `src/core/VENDOR.md`. Update path:
74
+ `/lt-dev:backend:update-nest-server-core` (Claude Code agent).
75
+
76
+ ### Creating projects
77
+
78
+ ```bash
79
+ # npm mode (classic, default)
80
+ $ lt fullstack init --name myapp --frontend nuxt --api-mode Rest
81
+
82
+ # vendor mode, HEAD of upstream
83
+ $ lt fullstack init --name myapp --frontend nuxt --api-mode Rest \
84
+ --framework-mode vendor
85
+
86
+ # vendor mode, pinned to a specific upstream branch or tag
87
+ $ lt fullstack init --name myapp --framework-mode vendor \
88
+ --framework-upstream-branch 11.24.1
89
+
90
+ # dry-run: print the plan without touching the filesystem
91
+ $ lt fullstack init --name myapp --framework-mode vendor --dry-run --noConfirm
92
+
93
+ # standalone api project (vendor mode works here too)
94
+ $ lt server create --name myapp --framework-mode vendor
95
+ ```
96
+
97
+ ### Working on an existing project
98
+
99
+ All `lt server …` commands (module, object, addProp, test, permissions)
100
+ **auto-detect** the framework mode via `src/core/VENDOR.md` and generate
101
+ the correct import syntax automatically. You never pass `--framework-mode`
102
+ after `init`; it is persisted in the project's `lt.config.json`.
103
+
104
+ ```bash
105
+ # inside projects/api — generates relative or bare imports automatically
106
+ $ lt server module --name Product --controller Rest
107
+
108
+ # shows the mode + project type
109
+ $ lt status
110
+
111
+ # prints the mode-specific update instructions
112
+ $ lt fullstack update
113
+ ```
114
+
115
+ ### Vendor-mode housekeeping
116
+
117
+ Vendor-mode projects ship three maintenance scripts under `scripts/vendor/`:
118
+
119
+ | Script | Purpose | Invocation |
120
+ |---|---|---|
121
+ | `check-vendor-freshness.mjs` | Non-blocking warning when upstream has a newer release than the current baseline | `pnpm run check:vendor-freshness` (auto-invoked by `pnpm run check` / `check:fix` / `check:naf`) |
122
+ | `sync-from-upstream.ts` | Diff generator consumed by the `nest-server-core-updater` Claude Code agent | `pnpm run vendor:sync` |
123
+ | `propose-upstream-pr.ts` | Patch-list generator consumed by the `nest-server-core-contributor` agent | `pnpm run vendor:propose-upstream` |
124
+
125
+ The vendor-mode baseline (upstream version + commit SHA) is recorded in
126
+ `src/core/VENDOR.md`. Log any substantial local patch there so the updater
127
+ agent can classify it at sync time.
128
+
129
+ ### Integration test
130
+
131
+ A full end-to-end smoke test for all four supported init combinations
132
+ (`npm/Rest`, `vendor/Rest`, `vendor/GraphQL`, `vendor/Both`) ships with the
133
+ CLI:
134
+
135
+ ```bash
136
+ $ pnpm run test:vendor-init
137
+ ```
138
+
139
+ Each scenario runs init → module → object → addProp → test → tsc → build →
140
+ migrate:list and asserts ~30 structural + functional invariants per scenario.
141
+ Run this before releasing a new CLI version to catch upstream drift early.
142
+
58
143
  ## Configuration
59
144
 
60
145
  The CLI supports project-specific configuration via `lt.config` files. This allows you to set default values for commands, reducing repetitive input.
@@ -56,9 +56,11 @@ const KNOWN_KEYS = {
56
56
  apiCopy: 'string',
57
57
  apiLink: 'string',
58
58
  apiMode: ['Rest', 'GraphQL', 'Both'],
59
+ frameworkMode: ['npm', 'vendor'],
59
60
  frontend: ['angular', 'nuxt'],
60
61
  frontendBranch: 'string',
61
62
  frontendCopy: 'string',
63
+ frontendFrameworkMode: ['npm', 'vendor'],
62
64
  frontendLink: 'string',
63
65
  git: 'boolean',
64
66
  gitLink: 'string',
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const frontend_framework_detection_1 = require("../../lib/frontend-framework-detection");
13
+ /**
14
+ * Convert an existing frontend project between npm mode and vendor mode.
15
+ *
16
+ * Usage:
17
+ * lt frontend convert-mode --to vendor [--upstream-branch 1.5.3]
18
+ * lt frontend convert-mode --to npm [--version 1.5.3]
19
+ */
20
+ const ConvertModeCommand = {
21
+ description: 'Convert app framework mode',
22
+ hidden: false,
23
+ name: 'convert-mode',
24
+ run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
25
+ const { filesystem, frontendHelper, parameters, print: { error, info, spin, success, warning }, prompt: { confirm }, } = toolbox;
26
+ // Handle --help-json flag
27
+ if (toolbox.tools.helpJson({
28
+ description: 'Convert frontend project between npm and vendor framework modes',
29
+ name: 'convert-mode',
30
+ options: [
31
+ {
32
+ description: 'Target mode',
33
+ flag: '--to',
34
+ required: true,
35
+ type: 'string',
36
+ values: ['vendor', 'npm'],
37
+ },
38
+ {
39
+ description: 'Upstream branch/tag to vendor from (only with --to vendor)',
40
+ flag: '--upstream-branch',
41
+ required: false,
42
+ type: 'string',
43
+ },
44
+ {
45
+ description: 'nuxt-extensions version to install (only with --to npm, default: from VENDOR.md baseline)',
46
+ flag: '--version',
47
+ required: false,
48
+ type: 'string',
49
+ },
50
+ {
51
+ default: false,
52
+ description: 'Skip confirmation prompt',
53
+ flag: '--noConfirm',
54
+ required: false,
55
+ type: 'boolean',
56
+ },
57
+ {
58
+ default: false,
59
+ description: 'Show the resolved plan without making any changes',
60
+ flag: '--dry-run',
61
+ required: false,
62
+ type: 'boolean',
63
+ },
64
+ ],
65
+ })) {
66
+ return;
67
+ }
68
+ const targetMode = parameters.options.to;
69
+ if (!targetMode || !['npm', 'vendor'].includes(targetMode)) {
70
+ error('Missing or invalid --to flag. Use: --to vendor or --to npm');
71
+ return;
72
+ }
73
+ // Find the frontend project root
74
+ const cwd = filesystem.cwd();
75
+ const appDir = (0, frontend_framework_detection_1.findAppDir)(cwd);
76
+ if (!appDir) {
77
+ error('Could not find a nuxt.config.ts in the current directory or any parent. Are you inside a Nuxt project?');
78
+ return;
79
+ }
80
+ // Detect current mode
81
+ const currentMode = (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(appDir);
82
+ info(`Detected current mode: ${currentMode}`);
83
+ if (currentMode === targetMode) {
84
+ warning(`Project is already in ${targetMode} mode. Nothing to do.`);
85
+ return;
86
+ }
87
+ // Dry-run: print the resolved plan and exit without any disk changes.
88
+ const dryRun = parameters.options['dry-run'] === true || parameters.options['dry-run'] === 'true';
89
+ if (dryRun) {
90
+ info('');
91
+ info('Dry-run plan:');
92
+ info(` appDir: ${appDir}`);
93
+ info(` currentMode: ${currentMode}`);
94
+ info(` targetMode: ${targetMode}`);
95
+ if (targetMode === 'vendor') {
96
+ const upstreamBranch = parameters.options['upstream-branch'];
97
+ info(` upstreamBranch: ${upstreamBranch || '(auto-detect from package.json)'}`);
98
+ info('');
99
+ info('Would execute:');
100
+ info(' 1. Clone @lenne.tech/nuxt-extensions → /tmp/lt-vendor-nuxt-ext-*');
101
+ info(' 2. Copy src/module.ts + src/runtime/ → app/core/');
102
+ info(' 3. Rewrite nuxt.config.ts: @lenne.tech/nuxt-extensions → ./app/core/module');
103
+ info(' 4. Codemod consumer imports (app/**/*.{ts,vue}, tests/**/*.ts)');
104
+ info(' 5. Remove @lenne.tech/nuxt-extensions from package.json');
105
+ info(' 6. Add check:vendor-freshness script');
106
+ info(' 7. Create app/core/VENDOR.md with baseline metadata');
107
+ info(' 8. Prepend vendor-mode notice to CLAUDE.md');
108
+ }
109
+ else {
110
+ const targetVersion = parameters.options.version;
111
+ info(` targetVersion: ${targetVersion || '(from VENDOR.md baseline)'}`);
112
+ info('');
113
+ info('Would execute:');
114
+ info(' 1. Read baseline version from app/core/VENDOR.md');
115
+ info(' 2. Warn if local patches exist in VENDOR.md');
116
+ info(' 3. Rewrite consumer imports: relative → @lenne.tech/nuxt-extensions');
117
+ info(' 4. Delete app/core/');
118
+ info(' 5. Restore @lenne.tech/nuxt-extensions in package.json');
119
+ info(' 6. Rewrite nuxt.config.ts: ./app/core/module → @lenne.tech/nuxt-extensions');
120
+ info(' 7. Remove vendor scripts and CLAUDE.md marker');
121
+ }
122
+ info('');
123
+ return `frontend convert-mode dry-run (${currentMode} → ${targetMode})`;
124
+ }
125
+ // Confirm
126
+ const noConfirm = parameters.options.noConfirm;
127
+ if (!noConfirm) {
128
+ const proceed = yield confirm(`Convert project from ${currentMode} mode to ${targetMode} mode?\n` +
129
+ ` Project: ${appDir}\n` +
130
+ ` This will modify nuxt.config.ts, package.json, imports, and CLAUDE.md.`);
131
+ if (!proceed) {
132
+ info('Aborted.');
133
+ return;
134
+ }
135
+ }
136
+ // Execute conversion
137
+ if (targetMode === 'vendor') {
138
+ // npm → vendor
139
+ const upstreamBranch = parameters.options['upstream-branch'];
140
+ // Auto-detect version from current @lenne.tech/nuxt-extensions dep
141
+ let branch = upstreamBranch;
142
+ if (!branch) {
143
+ try {
144
+ const pkg = filesystem.read(`${appDir}/package.json`, 'json');
145
+ const deps = Object.assign(Object.assign({}, ((pkg === null || pkg === void 0 ? void 0 : pkg.dependencies) || {})), ((pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies) || {}));
146
+ const version = deps['@lenne.tech/nuxt-extensions'];
147
+ if (version) {
148
+ // Strip semver range chars (^, ~, >=, etc.) to get the bare version
149
+ branch = version.replace(/^[^0-9]*/, '');
150
+ info(`Auto-detected @lenne.tech/nuxt-extensions version: ${branch}`);
151
+ }
152
+ }
153
+ catch (_a) {
154
+ // Will use HEAD
155
+ }
156
+ }
157
+ const spinner = spin('Converting to vendor mode...');
158
+ try {
159
+ yield frontendHelper.convertAppToVendorMode({
160
+ dest: appDir,
161
+ upstreamBranch: branch,
162
+ });
163
+ spinner.succeed('Converted to vendor mode successfully.');
164
+ success('\nNext steps:');
165
+ info(' 1. Run: pnpm install');
166
+ info(' 2. Run: pnpm run build (or nuxt build)');
167
+ info(' 3. Commit the changes');
168
+ }
169
+ catch (err) {
170
+ spinner.fail(`Conversion failed: ${err.message}`);
171
+ }
172
+ }
173
+ else {
174
+ // vendor → npm
175
+ const targetVersion = parameters.options.version;
176
+ const spinner = spin('Converting to npm mode...');
177
+ try {
178
+ yield frontendHelper.convertAppToNpmMode({
179
+ dest: appDir,
180
+ targetVersion,
181
+ });
182
+ spinner.succeed('Converted to npm mode successfully.');
183
+ success('\nNext steps:');
184
+ info(' 1. Run: pnpm install');
185
+ info(' 2. Run: pnpm run build (or nuxt build)');
186
+ info(' 3. Commit the changes');
187
+ }
188
+ catch (err) {
189
+ spinner.fail(`Conversion failed: ${err.message}`);
190
+ }
191
+ }
192
+ if (!parameters.options.fromGluegunMenu) {
193
+ process.exit();
194
+ }
195
+ return `converted frontend to ${targetMode} mode`;
196
+ }),
197
+ };
198
+ exports.default = ConvertModeCommand;