@lenne.tech/cli 1.10.0 → 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.
- package/README.md +5 -3
- package/build/commands/config/validate.js +2 -0
- package/build/commands/frontend/convert-mode.js +198 -0
- package/build/commands/fullstack/convert-mode.js +368 -0
- package/build/commands/fullstack/init.js +44 -2
- package/build/commands/fullstack/update.js +49 -1
- package/build/commands/server/convert-mode.js +197 -0
- package/build/commands/status.js +81 -2
- package/build/config/vendor-frontend-runtime-deps.json +4 -0
- package/build/extensions/frontend-helper.js +652 -0
- package/build/extensions/server.js +515 -68
- package/build/lib/frontend-framework-detection.js +129 -0
- package/docs/LT-ECOSYSTEM-GUIDE.md +973 -0
- package/docs/VENDOR-MODE-WORKFLOW.md +471 -0
- package/docs/commands.md +196 -0
- package/docs/lt.config.md +9 -7
- package/package.json +2 -1
- package/build/templates/vendor-scripts/check-vendor-freshness.mjs +0 -131
- package/build/templates/vendor-scripts/propose-upstream-pr.ts +0 -269
- package/build/templates/vendor-scripts/sync-from-upstream.ts +0 -250
|
@@ -18,7 +18,7 @@ const NewCommand = {
|
|
|
18
18
|
hidden: false,
|
|
19
19
|
name: 'init',
|
|
20
20
|
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
21
|
+
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;
|
|
22
22
|
// Retrieve the tools we need
|
|
23
23
|
const { config, filesystem, frontendHelper, git, helper, parameters, patching, print: { error, info, spin, success }, prompt: { ask, confirm }, server, strings: { kebabCase }, system, } = toolbox;
|
|
24
24
|
// Start timer
|
|
@@ -45,7 +45,7 @@ const NewCommand = {
|
|
|
45
45
|
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;
|
|
46
46
|
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;
|
|
47
47
|
// Parse CLI arguments
|
|
48
|
-
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-link': cliFrontendLink, git: cliGit, 'git-link': cliGitLink, name: cliName, } = parameters.options;
|
|
48
|
+
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
49
|
const dryRun = cliDryRun === true || cliDryRun === 'true';
|
|
50
50
|
const frameworkUpstreamBranch = typeof cliFrameworkUpstreamBranch === 'string' && cliFrameworkUpstreamBranch.length > 0
|
|
51
51
|
? cliFrameworkUpstreamBranch
|
|
@@ -181,6 +181,27 @@ const NewCommand = {
|
|
|
181
181
|
});
|
|
182
182
|
frameworkMode = frameworkModeChoice.frameworkMode.startsWith('vendor') ? 'vendor' : 'npm';
|
|
183
183
|
}
|
|
184
|
+
// ── Frontend framework mode ─────────────────────────────────────────
|
|
185
|
+
const configFrontendFrameworkMode = (_0 = (_z = ltConfig === null || ltConfig === void 0 ? void 0 : ltConfig.commands) === null || _z === void 0 ? void 0 : _z.fullstack) === null || _0 === void 0 ? void 0 : _0.frontendFrameworkMode;
|
|
186
|
+
let frontendFrameworkMode;
|
|
187
|
+
if (cliFrontendFrameworkMode === 'npm' || cliFrontendFrameworkMode === 'vendor') {
|
|
188
|
+
frontendFrameworkMode = cliFrontendFrameworkMode;
|
|
189
|
+
}
|
|
190
|
+
else if (cliFrontendFrameworkMode) {
|
|
191
|
+
error(`Invalid --frontend-framework-mode value "${cliFrontendFrameworkMode}". Use "npm" or "vendor".`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
else if (configFrontendFrameworkMode === 'npm' || configFrontendFrameworkMode === 'vendor') {
|
|
195
|
+
frontendFrameworkMode = configFrontendFrameworkMode;
|
|
196
|
+
info(`Using frontend framework mode from lt.config: ${frontendFrameworkMode}`);
|
|
197
|
+
}
|
|
198
|
+
else if (noConfirm) {
|
|
199
|
+
frontendFrameworkMode = 'npm';
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// Default to npm without asking (unless user sets it explicitly)
|
|
203
|
+
frontendFrameworkMode = 'npm';
|
|
204
|
+
}
|
|
184
205
|
// Determine remote push settings with priority: CLI > config > interactive
|
|
185
206
|
// Git is always initialized; the question is whether to push to a remote
|
|
186
207
|
let pushToRemote = false;
|
|
@@ -251,6 +272,7 @@ const NewCommand = {
|
|
|
251
272
|
info(` frontend: ${frontend}`);
|
|
252
273
|
info(` apiMode: ${apiMode}`);
|
|
253
274
|
info(` frameworkMode: ${frameworkMode}`);
|
|
275
|
+
info(` frontendFrameworkMode: ${frontendFrameworkMode}`);
|
|
254
276
|
if (frameworkUpstreamBranch) {
|
|
255
277
|
info(` frameworkUpstreamBranch: ${frameworkUpstreamBranch}`);
|
|
256
278
|
}
|
|
@@ -282,6 +304,11 @@ const NewCommand = {
|
|
|
282
304
|
info(` 3. clone nest-server-starter → ${projectDir}/projects/api`);
|
|
283
305
|
info(` 4. run processApiMode(${apiMode})`);
|
|
284
306
|
}
|
|
307
|
+
if (frontendFrameworkMode === 'vendor') {
|
|
308
|
+
info(` M1. clone @lenne.tech/nuxt-extensions → /tmp`);
|
|
309
|
+
info(` M2. vendor app/core/ (module.ts + runtime/) + codemod consumer imports`);
|
|
310
|
+
info(` M3. rewrite nuxt.config.ts module entry`);
|
|
311
|
+
}
|
|
285
312
|
info(' N. pnpm install + initial git commit');
|
|
286
313
|
info('');
|
|
287
314
|
return `fullstack init dry-run (${frameworkMode} / ${apiMode})`;
|
|
@@ -364,6 +391,21 @@ const NewCommand = {
|
|
|
364
391
|
if (frontendResult.method !== 'link') {
|
|
365
392
|
frontendHelper.patchFrontendEnv(frontendDest, projectDir);
|
|
366
393
|
}
|
|
394
|
+
// ── Frontend vendoring (if requested) ───────────────────────────────
|
|
395
|
+
if (isNuxt && frontendFrameworkMode === 'vendor' && frontendResult.method !== 'link') {
|
|
396
|
+
const vendorSpinner = spin('Converting frontend to vendor mode...');
|
|
397
|
+
try {
|
|
398
|
+
yield frontendHelper.convertAppCloneToVendored({
|
|
399
|
+
dest: frontendDest,
|
|
400
|
+
projectName: name,
|
|
401
|
+
});
|
|
402
|
+
vendorSpinner.succeed('Frontend converted to vendor mode (app/core/)');
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
vendorSpinner.fail(`Frontend vendor conversion failed: ${err.message}`);
|
|
406
|
+
toolbox.print.warning('Continuing with npm mode for frontend.');
|
|
407
|
+
}
|
|
408
|
+
}
|
|
367
409
|
// Remove gitkeep file
|
|
368
410
|
filesystem.remove(`${projectDir}/projects/.gitkeep`);
|
|
369
411
|
// Integrate files
|
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const path_1 = require("path");
|
|
13
13
|
const framework_detection_1 = require("../../lib/framework-detection");
|
|
14
|
+
const frontend_framework_detection_1 = require("../../lib/frontend-framework-detection");
|
|
14
15
|
/**
|
|
15
16
|
* Update a fullstack workspace — mode-aware.
|
|
16
17
|
*
|
|
@@ -120,10 +121,57 @@ const NewCommand = {
|
|
|
120
121
|
success(' The nest-server-updater agent auto-detects vendor projects');
|
|
121
122
|
success(' and delegates to nest-server-core-updater when VENDOR.md is present.');
|
|
122
123
|
}
|
|
124
|
+
// ── Frontend mode-aware instructions ──────────────────────────────
|
|
123
125
|
info('');
|
|
124
126
|
info(colors.dim('─'.repeat(60)));
|
|
125
127
|
info('');
|
|
126
|
-
|
|
128
|
+
// Detect frontend project
|
|
129
|
+
const appCandidates = [
|
|
130
|
+
(0, path_1.join)(cwd, 'projects', 'app'),
|
|
131
|
+
(0, path_1.join)(cwd, 'packages', 'app'),
|
|
132
|
+
].filter((p) => Boolean(p));
|
|
133
|
+
let appDir;
|
|
134
|
+
for (const candidate of appCandidates) {
|
|
135
|
+
if (filesystem.exists((0, path_1.join)(candidate, 'nuxt.config.ts')) || filesystem.exists((0, path_1.join)(candidate, 'package.json'))) {
|
|
136
|
+
appDir = candidate;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (appDir) {
|
|
141
|
+
const frontendMode = (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(appDir);
|
|
142
|
+
const frontendVendored = (0, frontend_framework_detection_1.isVendoredAppProject)(appDir);
|
|
143
|
+
info(` App project: ${appDir}`);
|
|
144
|
+
info(` Frontend framework mode: ${frontendMode}${frontendVendored ? ' (app/core/VENDOR.md present)' : ''}`);
|
|
145
|
+
info('');
|
|
146
|
+
if (frontendMode === 'vendor') {
|
|
147
|
+
info(colors.bold('Frontend vendor-mode update flow:'));
|
|
148
|
+
info('');
|
|
149
|
+
info(' The nuxt-extensions module lives directly in this project at');
|
|
150
|
+
info(' app/core/');
|
|
151
|
+
info(' and is managed as first-class project code.');
|
|
152
|
+
info('');
|
|
153
|
+
info(colors.bold(' Recommended update commands:'));
|
|
154
|
+
info('');
|
|
155
|
+
info(' /lt-dev:frontend:update-nuxt-extensions-core');
|
|
156
|
+
info('');
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
info(colors.bold('Frontend npm-mode update flow:'));
|
|
160
|
+
info('');
|
|
161
|
+
info(' /lt-dev:fullstack:update --skip-backend');
|
|
162
|
+
info('');
|
|
163
|
+
info(' (or manually: pnpm update @lenne.tech/nuxt-extensions)');
|
|
164
|
+
info('');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
info('');
|
|
168
|
+
info(colors.bold('For a comprehensive update of everything, use:'));
|
|
169
|
+
info('');
|
|
170
|
+
info(' /lt-dev:fullstack:update-all');
|
|
171
|
+
info('');
|
|
172
|
+
info(colors.dim('─'.repeat(60)));
|
|
173
|
+
info('');
|
|
174
|
+
return `fullstack update (backend: ${mode}, frontend: ${appDir ? (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(appDir) : 'not found'})`;
|
|
127
175
|
}),
|
|
128
176
|
};
|
|
129
177
|
exports.default = NewCommand;
|
|
@@ -0,0 +1,197 @@
|
|
|
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 framework_detection_1 = require("../../lib/framework-detection");
|
|
13
|
+
/**
|
|
14
|
+
* Convert an existing API project between npm mode and vendor mode.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* lt server convert-mode --to vendor [--upstream-branch 11.24.2]
|
|
18
|
+
* lt server convert-mode --to npm [--version 11.24.2]
|
|
19
|
+
*/
|
|
20
|
+
const ConvertModeCommand = {
|
|
21
|
+
description: 'Convert API project between npm and vendor framework modes',
|
|
22
|
+
hidden: false,
|
|
23
|
+
name: 'convert-mode',
|
|
24
|
+
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
const { filesystem, parameters, print: { error, info, spin, success, warning }, prompt: { confirm }, server, } = toolbox;
|
|
26
|
+
// Handle --help-json flag
|
|
27
|
+
if (toolbox.tools.helpJson({
|
|
28
|
+
description: 'Convert API 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: 'nest-server 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 API project root
|
|
74
|
+
const cwd = filesystem.cwd();
|
|
75
|
+
const projectDir = (0, framework_detection_1.findProjectDir)(cwd);
|
|
76
|
+
if (!projectDir) {
|
|
77
|
+
error('Could not find a package.json in the current directory or any parent. Are you inside an API project?');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Detect current mode
|
|
81
|
+
const currentMode = (0, framework_detection_1.detectFrameworkMode)(projectDir);
|
|
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(` projectDir: ${projectDir}`);
|
|
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/nest-server → /tmp/lt-vendor-nest-server-*');
|
|
101
|
+
info(' 2. Copy src/core/, src/index.ts, src/core.module.ts, test/, templates/, types/ → src/core/');
|
|
102
|
+
info(' 3. Apply flatten-fix (index.ts, core.module.ts, test.helper.ts)');
|
|
103
|
+
info(' 4. Rewrite consumer imports: @lenne.tech/nest-server → relative paths');
|
|
104
|
+
info(' 5. Merge upstream deps dynamically into package.json');
|
|
105
|
+
info(' 6. Rewrite migrate scripts to use local bin/migrate.js');
|
|
106
|
+
info(' 7. Add check:vendor-freshness script');
|
|
107
|
+
info(' 8. Create src/core/VENDOR.md with baseline metadata');
|
|
108
|
+
info(' 9. Prepend vendor-mode notice to CLAUDE.md');
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const targetVersion = parameters.options.version;
|
|
112
|
+
info(` targetVersion: ${targetVersion || '(from VENDOR.md baseline)'}`);
|
|
113
|
+
info('');
|
|
114
|
+
info('Would execute:');
|
|
115
|
+
info(' 1. Read baseline version from src/core/VENDOR.md');
|
|
116
|
+
info(' 2. Warn if local patches exist in VENDOR.md');
|
|
117
|
+
info(' 3. Rewrite consumer imports: relative → @lenne.tech/nest-server');
|
|
118
|
+
info(' 4. Delete src/core/');
|
|
119
|
+
info(' 5. Restore @lenne.tech/nest-server in package.json');
|
|
120
|
+
info(' 6. Restore migrate scripts to node_modules paths');
|
|
121
|
+
info(' 7. Remove vendor artifacts and CLAUDE.md marker');
|
|
122
|
+
}
|
|
123
|
+
info('');
|
|
124
|
+
return `server convert-mode dry-run (${currentMode} → ${targetMode})`;
|
|
125
|
+
}
|
|
126
|
+
// Confirm
|
|
127
|
+
const noConfirm = parameters.options.noConfirm;
|
|
128
|
+
if (!noConfirm) {
|
|
129
|
+
const proceed = yield confirm(`Convert project from ${currentMode} mode to ${targetMode} mode?\n` +
|
|
130
|
+
` Project: ${projectDir}\n` +
|
|
131
|
+
` This will modify package.json, imports, tsconfig, and CLAUDE.md.`);
|
|
132
|
+
if (!proceed) {
|
|
133
|
+
info('Aborted.');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Execute conversion
|
|
138
|
+
if (targetMode === 'vendor') {
|
|
139
|
+
// npm → vendor
|
|
140
|
+
const upstreamBranch = parameters.options['upstream-branch'];
|
|
141
|
+
// Auto-detect version from current @lenne.tech/nest-server dep
|
|
142
|
+
let branch = upstreamBranch;
|
|
143
|
+
if (!branch) {
|
|
144
|
+
try {
|
|
145
|
+
const pkg = filesystem.read(`${projectDir}/package.json`, 'json');
|
|
146
|
+
const deps = Object.assign(Object.assign({}, ((pkg === null || pkg === void 0 ? void 0 : pkg.dependencies) || {})), ((pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies) || {}));
|
|
147
|
+
const version = deps['@lenne.tech/nest-server'];
|
|
148
|
+
if (version) {
|
|
149
|
+
// Strip semver range chars (^, ~, >=, etc.) to get the bare version
|
|
150
|
+
branch = version.replace(/^[^0-9]*/, '');
|
|
151
|
+
info(`Auto-detected @lenne.tech/nest-server version: ${branch}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (_a) {
|
|
155
|
+
// Will prompt or use HEAD
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const spinner = spin('Converting to vendor mode...');
|
|
159
|
+
try {
|
|
160
|
+
yield server.convertToVendorMode({
|
|
161
|
+
dest: projectDir,
|
|
162
|
+
upstreamBranch: branch,
|
|
163
|
+
});
|
|
164
|
+
spinner.succeed('Converted to vendor mode successfully.');
|
|
165
|
+
success('\nNext steps:');
|
|
166
|
+
info(' 1. Run: pnpm install');
|
|
167
|
+
info(' 2. Run: pnpm exec tsc --noEmit');
|
|
168
|
+
info(' 3. Run: pnpm test');
|
|
169
|
+
info(' 4. Commit the changes');
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
spinner.fail(`Conversion failed: ${err.message}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// vendor → npm
|
|
177
|
+
const targetVersion = parameters.options.version;
|
|
178
|
+
const spinner = spin('Converting to npm mode...');
|
|
179
|
+
try {
|
|
180
|
+
yield server.convertToNpmMode({
|
|
181
|
+
dest: projectDir,
|
|
182
|
+
targetVersion,
|
|
183
|
+
});
|
|
184
|
+
spinner.succeed('Converted to npm mode successfully.');
|
|
185
|
+
success('\nNext steps:');
|
|
186
|
+
info(' 1. Run: pnpm install');
|
|
187
|
+
info(' 2. Run: pnpm exec tsc --noEmit');
|
|
188
|
+
info(' 3. Run: pnpm test');
|
|
189
|
+
info(' 4. Commit the changes');
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
spinner.fail(`Conversion failed: ${err.message}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}),
|
|
196
|
+
};
|
|
197
|
+
exports.default = ConvertModeCommand;
|
package/build/commands/status.js
CHANGED
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const path_1 = require("path");
|
|
13
13
|
const framework_detection_1 = require("../lib/framework-detection");
|
|
14
|
+
const frontend_framework_detection_1 = require("../lib/frontend-framework-detection");
|
|
14
15
|
/**
|
|
15
16
|
* Show project status and context
|
|
16
17
|
*/
|
|
@@ -29,11 +30,13 @@ const StatusCommand = {
|
|
|
29
30
|
const projectInfo = {
|
|
30
31
|
configFiles: [],
|
|
31
32
|
frameworkMode: null,
|
|
33
|
+
frontendFrameworkMode: null,
|
|
32
34
|
gitBranch: null,
|
|
33
35
|
gitRoot: null,
|
|
34
36
|
hasGit: false,
|
|
35
37
|
hasLtConfig: false,
|
|
36
38
|
hasPackageJson: false,
|
|
39
|
+
monorepoSubprojects: [],
|
|
37
40
|
nodeVersion: null,
|
|
38
41
|
npmVersion: null,
|
|
39
42
|
packageName: null,
|
|
@@ -70,6 +73,10 @@ const StatusCommand = {
|
|
|
70
73
|
}
|
|
71
74
|
else if (deps['nuxt']) {
|
|
72
75
|
projectInfo.projectType = 'nuxt';
|
|
76
|
+
// Detect frontend framework mode if nuxt-extensions is present
|
|
77
|
+
if (deps['@lenne.tech/nuxt-extensions'] || (0, frontend_framework_detection_1.isVendoredAppProject)(cwd)) {
|
|
78
|
+
projectInfo.frontendFrameworkMode = (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(cwd);
|
|
79
|
+
}
|
|
73
80
|
}
|
|
74
81
|
else if (deps['@angular/core']) {
|
|
75
82
|
projectInfo.projectType = 'angular';
|
|
@@ -91,6 +98,52 @@ const StatusCommand = {
|
|
|
91
98
|
// Ignore parse errors
|
|
92
99
|
}
|
|
93
100
|
}
|
|
101
|
+
// Monorepo subproject detection: scan projects/api and projects/app for
|
|
102
|
+
// framework modes so that `lt status` at the monorepo root surfaces
|
|
103
|
+
// backend + frontend framework consumption modes even when the root
|
|
104
|
+
// itself is not a Nest/Nuxt project.
|
|
105
|
+
const monorepoCandidates = [
|
|
106
|
+
{ kind: 'backend', path: (0, path_1.join)(cwd, 'projects', 'api') },
|
|
107
|
+
{ kind: 'backend', path: (0, path_1.join)(cwd, 'packages', 'api') },
|
|
108
|
+
{ kind: 'frontend', path: (0, path_1.join)(cwd, 'projects', 'app') },
|
|
109
|
+
{ kind: 'frontend', path: (0, path_1.join)(cwd, 'packages', 'app') },
|
|
110
|
+
];
|
|
111
|
+
for (const candidate of monorepoCandidates) {
|
|
112
|
+
if (!filesystem.exists((0, path_1.join)(candidate.path, 'package.json')))
|
|
113
|
+
continue;
|
|
114
|
+
if (candidate.kind === 'backend') {
|
|
115
|
+
try {
|
|
116
|
+
const subPkg = JSON.parse(filesystem.read((0, path_1.join)(candidate.path, 'package.json')) || '{}');
|
|
117
|
+
const subDeps = Object.assign(Object.assign({}, subPkg.dependencies), subPkg.devDependencies);
|
|
118
|
+
if (subDeps['@lenne.tech/nest-server'] || (0, framework_detection_1.isVendoredProject)(candidate.path)) {
|
|
119
|
+
projectInfo.monorepoSubprojects.push({
|
|
120
|
+
frameworkMode: (0, framework_detection_1.detectFrameworkMode)(candidate.path),
|
|
121
|
+
kind: 'backend',
|
|
122
|
+
path: candidate.path,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (_d) {
|
|
127
|
+
// ignore
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
try {
|
|
132
|
+
const subPkg = JSON.parse(filesystem.read((0, path_1.join)(candidate.path, 'package.json')) || '{}');
|
|
133
|
+
const subDeps = Object.assign(Object.assign({}, subPkg.dependencies), subPkg.devDependencies);
|
|
134
|
+
if (subDeps['@lenne.tech/nuxt-extensions'] || (0, frontend_framework_detection_1.isVendoredAppProject)(candidate.path)) {
|
|
135
|
+
projectInfo.monorepoSubprojects.push({
|
|
136
|
+
frameworkMode: (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(candidate.path),
|
|
137
|
+
kind: 'frontend',
|
|
138
|
+
path: candidate.path,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (_e) {
|
|
143
|
+
// ignore
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
94
147
|
// Check for git
|
|
95
148
|
try {
|
|
96
149
|
const gitRoot = yield system.run('git rev-parse --show-toplevel 2>/dev/null');
|
|
@@ -101,7 +154,7 @@ const StatusCommand = {
|
|
|
101
154
|
projectInfo.gitBranch = (branch === null || branch === void 0 ? void 0 : branch.trim()) || null;
|
|
102
155
|
}
|
|
103
156
|
}
|
|
104
|
-
catch (
|
|
157
|
+
catch (_f) {
|
|
105
158
|
// Not a git repository
|
|
106
159
|
}
|
|
107
160
|
// Get Node/npm versions
|
|
@@ -109,7 +162,7 @@ const StatusCommand = {
|
|
|
109
162
|
projectInfo.nodeVersion = ((_a = (yield system.run('node --version 2>/dev/null'))) === null || _a === void 0 ? void 0 : _a.trim()) || null;
|
|
110
163
|
projectInfo.npmVersion = ((_b = (yield system.run('npm --version 2>/dev/null'))) === null || _b === void 0 ? void 0 : _b.trim()) || null;
|
|
111
164
|
}
|
|
112
|
-
catch (
|
|
165
|
+
catch (_g) {
|
|
113
166
|
// Ignore errors
|
|
114
167
|
}
|
|
115
168
|
// Display project info
|
|
@@ -132,6 +185,32 @@ const StatusCommand = {
|
|
|
132
185
|
: 'npm (@lenne.tech/nest-server dependency)';
|
|
133
186
|
info(` Framework: ${modeLabel}`);
|
|
134
187
|
}
|
|
188
|
+
if (projectInfo.frontendFrameworkMode) {
|
|
189
|
+
const frontendModeLabel = projectInfo.frontendFrameworkMode === 'vendor'
|
|
190
|
+
? 'vendor (app/core/, VENDOR.md)'
|
|
191
|
+
: 'npm (@lenne.tech/nuxt-extensions dependency)';
|
|
192
|
+
info(` Frontend Framework: ${frontendModeLabel}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Show monorepo subprojects if we detected any (typically at monorepo root)
|
|
196
|
+
if (projectInfo.monorepoSubprojects.length > 0) {
|
|
197
|
+
info('');
|
|
198
|
+
info(colors.bold('Monorepo Subprojects:'));
|
|
199
|
+
for (const sub of projectInfo.monorepoSubprojects) {
|
|
200
|
+
const relPath = sub.path.replace(`${cwd}/`, '');
|
|
201
|
+
if (sub.kind === 'backend') {
|
|
202
|
+
const label = sub.frameworkMode === 'vendor'
|
|
203
|
+
? 'vendor (src/core/, VENDOR.md)'
|
|
204
|
+
: 'npm (@lenne.tech/nest-server dependency)';
|
|
205
|
+
info(` Backend: ${relPath} → ${label}`);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const label = sub.frameworkMode === 'vendor'
|
|
209
|
+
? 'vendor (app/core/, VENDOR.md)'
|
|
210
|
+
: 'npm (@lenne.tech/nuxt-extensions dependency)';
|
|
211
|
+
info(` Frontend: ${relPath} → ${label}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
135
214
|
}
|
|
136
215
|
if (projectInfo.hasGit) {
|
|
137
216
|
info('');
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Upstream @lenne.tech/nuxt-extensions devDependencies that must be promoted to regular dependencies in vendor mode. Currently empty because nuxt-extensions has only @nuxt/kit as a direct dependency (which is handled explicitly during vendoring).",
|
|
3
|
+
"runtimeHelpers": []
|
|
4
|
+
}
|