@lenne.tech/cli 1.28.0 → 1.29.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.
@@ -9,9 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.help = void 0;
12
13
  const path_1 = require("path");
13
14
  const framework_detection_1 = require("../../lib/framework-detection");
14
15
  const frontend_framework_detection_1 = require("../../lib/frontend-framework-detection");
16
+ const vendor_claude_md_1 = require("../../lib/vendor-claude-md");
15
17
  /**
16
18
  * Convert both backend and frontend of a fullstack monorepo between
17
19
  * npm mode and vendor mode in a single command.
@@ -26,6 +28,71 @@ const frontend_framework_detection_1 = require("../../lib/frontend-framework-det
26
28
  * Orchestrates `lt server convert-mode` + `lt frontend convert-mode` with
27
29
  * auto-detection of `projects/api/` and `projects/app/` subdirectories.
28
30
  */
31
+ exports.help = {
32
+ description: 'Convert fullstack monorepo (backend + frontend) between npm and vendor modes',
33
+ name: 'convert-mode',
34
+ options: [
35
+ {
36
+ description: 'Target mode',
37
+ flag: '--to',
38
+ required: true,
39
+ type: 'string',
40
+ values: ['vendor', 'npm'],
41
+ },
42
+ {
43
+ description: 'Backend upstream branch/tag (only with --to vendor, e.g. "11.24.3")',
44
+ flag: '--framework-upstream-branch',
45
+ required: false,
46
+ type: 'string',
47
+ },
48
+ {
49
+ description: 'Frontend upstream branch/tag (only with --to vendor, e.g. "1.5.3")',
50
+ flag: '--frontend-framework-upstream-branch',
51
+ required: false,
52
+ type: 'string',
53
+ },
54
+ {
55
+ description: 'Backend version to install (only with --to npm, default: from VENDOR.md baseline)',
56
+ flag: '--framework-version',
57
+ required: false,
58
+ type: 'string',
59
+ },
60
+ {
61
+ description: 'Frontend version to install (only with --to npm, default: from VENDOR.md baseline)',
62
+ flag: '--frontend-framework-version',
63
+ required: false,
64
+ type: 'string',
65
+ },
66
+ {
67
+ default: false,
68
+ description: 'Skip backend conversion',
69
+ flag: '--skip-backend',
70
+ required: false,
71
+ type: 'boolean',
72
+ },
73
+ {
74
+ default: false,
75
+ description: 'Skip frontend conversion',
76
+ flag: '--skip-frontend',
77
+ required: false,
78
+ type: 'boolean',
79
+ },
80
+ {
81
+ default: false,
82
+ description: 'Show the resolved plan without making any changes',
83
+ flag: '--dry-run',
84
+ required: false,
85
+ type: 'boolean',
86
+ },
87
+ {
88
+ default: false,
89
+ description: 'Skip confirmation prompt',
90
+ flag: '--noConfirm',
91
+ required: false,
92
+ type: 'boolean',
93
+ },
94
+ ],
95
+ };
29
96
  const ConvertModeCommand = {
30
97
  description: 'Convert fullstack monorepo between npm and vendor modes',
31
98
  hidden: false,
@@ -33,71 +100,7 @@ const ConvertModeCommand = {
33
100
  run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
34
101
  const { filesystem, frontendHelper, parameters, print: { colors, error, info, spin, success, warning }, prompt: { confirm }, server, } = toolbox;
35
102
  // Handle --help-json flag
36
- if (toolbox.tools.helpJson({
37
- description: 'Convert fullstack monorepo (backend + frontend) between npm and vendor modes',
38
- name: 'convert-mode',
39
- options: [
40
- {
41
- description: 'Target mode',
42
- flag: '--to',
43
- required: true,
44
- type: 'string',
45
- values: ['vendor', 'npm'],
46
- },
47
- {
48
- description: 'Backend upstream branch/tag (only with --to vendor, e.g. "11.24.3")',
49
- flag: '--framework-upstream-branch',
50
- required: false,
51
- type: 'string',
52
- },
53
- {
54
- description: 'Frontend upstream branch/tag (only with --to vendor, e.g. "1.5.3")',
55
- flag: '--frontend-framework-upstream-branch',
56
- required: false,
57
- type: 'string',
58
- },
59
- {
60
- description: 'Backend version to install (only with --to npm, default: from VENDOR.md baseline)',
61
- flag: '--framework-version',
62
- required: false,
63
- type: 'string',
64
- },
65
- {
66
- description: 'Frontend version to install (only with --to npm, default: from VENDOR.md baseline)',
67
- flag: '--frontend-framework-version',
68
- required: false,
69
- type: 'string',
70
- },
71
- {
72
- default: false,
73
- description: 'Skip backend conversion',
74
- flag: '--skip-backend',
75
- required: false,
76
- type: 'boolean',
77
- },
78
- {
79
- default: false,
80
- description: 'Skip frontend conversion',
81
- flag: '--skip-frontend',
82
- required: false,
83
- type: 'boolean',
84
- },
85
- {
86
- default: false,
87
- description: 'Show the resolved plan without making any changes',
88
- flag: '--dry-run',
89
- required: false,
90
- type: 'boolean',
91
- },
92
- {
93
- default: false,
94
- description: 'Skip confirmation prompt',
95
- flag: '--noConfirm',
96
- required: false,
97
- type: 'boolean',
98
- },
99
- ],
100
- })) {
103
+ if (toolbox.tools.helpJson(exports.help)) {
101
104
  return;
102
105
  }
103
106
  const targetMode = parameters.options.to;
@@ -348,6 +351,23 @@ const ConvertModeCommand = {
348
351
  }
349
352
  info('');
350
353
  success('All conversions completed successfully.');
354
+ // ── Sync vendor notice blocks, including the monorepo root CLAUDE.md ───
355
+ // The per-subproject CLAUDE.md blocks are written by the server/frontend
356
+ // converters; this additionally maintains the workspace root CLAUDE.md —
357
+ // the entry point Claude reads first — and keeps everything idempotent.
358
+ const backendVendorNow = backendDir ? (0, framework_detection_1.detectFrameworkMode)(backendDir) === 'vendor' : false;
359
+ const frontendVendorNow = frontendDir ? (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(frontendDir) === 'vendor' : false;
360
+ const changedClaudeMd = (0, vendor_claude_md_1.healVendorClaudeMd)(filesystem, {
361
+ apiDir: backendDir,
362
+ appDir: frontendDir,
363
+ backendVendor: backendVendorNow,
364
+ frontendVendor: frontendVendorNow,
365
+ workspaceRoot: cwd,
366
+ });
367
+ if (changedClaudeMd.length > 0) {
368
+ info('');
369
+ success(`Synced vendor notice in ${changedClaudeMd.length} CLAUDE.md file(s) (incl. monorepo root).`);
370
+ }
351
371
  info('');
352
372
  info(colors.bold('Next steps:'));
353
373
  info(' 1. Run: pnpm install (from monorepo root)');
@@ -18,6 +18,7 @@ const dev_migrate_helper_1 = require("../../lib/dev-migrate-helper");
18
18
  const dev_project_1 = require("../../lib/dev-project");
19
19
  const hoist_workspace_pnpm_config_1 = require("../../lib/hoist-workspace-pnpm-config");
20
20
  const package_name_1 = require("../../lib/package-name");
21
+ const vendor_claude_md_1 = require("../../lib/vendor-claude-md");
21
22
  const workspace_integration_1 = require("../../lib/workspace-integration");
22
23
  const add_api_1 = __importDefault(require("./add-api"));
23
24
  const add_app_1 = __importDefault(require("./add-app"));
@@ -641,6 +642,17 @@ const NewCommand = {
641
642
  if (!experimental && isNuxt && filesystem.isDirectory(`${projectDir}/projects/app`)) {
642
643
  yield toolbox.apiMode.formatProject(`${projectDir}/projects/app`);
643
644
  }
645
+ // Sync the vendor-mode notice blocks across all CLAUDE.md files,
646
+ // including the monorepo root — so a freshly scaffolded vendor project
647
+ // tells Claude (and humans) how to update/contribute the vendored core
648
+ // from the very first commit. Idempotent / no-op for npm-mode projects.
649
+ (0, vendor_claude_md_1.healVendorClaudeMd)(filesystem, {
650
+ apiDir: `${projectDir}/projects/api`,
651
+ appDir: `${projectDir}/projects/app`,
652
+ backendVendor: frameworkMode === 'vendor',
653
+ frontendVendor: frontendFrameworkMode === 'vendor',
654
+ workspaceRoot: projectDir,
655
+ });
644
656
  // Create initial commit after everything is set up
645
657
  try {
646
658
  yield system.run(`cd ${projectDir} && git add . && git commit -m "Initial commit"`);
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const path_1 = require("path");
13
13
  const framework_detection_1 = require("../../lib/framework-detection");
14
14
  const frontend_framework_detection_1 = require("../../lib/frontend-framework-detection");
15
+ const vendor_claude_md_1 = require("../../lib/vendor-claude-md");
15
16
  /**
16
17
  * Update a fullstack workspace — mode-aware.
17
18
  *
@@ -161,6 +162,29 @@ const NewCommand = {
161
162
  info('');
162
163
  }
163
164
  }
165
+ // ── Self-heal: sync the vendor-mode notice blocks in all CLAUDE.md ────
166
+ //
167
+ // `lt fullstack update` doubles as a doc-sync: it (re)writes the vendor
168
+ // notice blocks so pre-existing or drifted projects gain the correct
169
+ // pointers — backend `projects/api/CLAUDE.md`, frontend
170
+ // `projects/app/CLAUDE.md`, and the monorepo root `CLAUDE.md` (the entry
171
+ // point Claude reads first). Idempotent: a no-op when already correct.
172
+ const frontendModeForHeal = appDir ? (0, frontend_framework_detection_1.detectFrontendFrameworkMode)(appDir) : undefined;
173
+ const isWorkspace = apiDir !== cwd || (!!appDir && appDir !== cwd);
174
+ const changedClaudeMd = (0, vendor_claude_md_1.healVendorClaudeMd)(filesystem, {
175
+ apiDir,
176
+ appDir,
177
+ backendVendor: mode === 'vendor',
178
+ frontendVendor: frontendModeForHeal === 'vendor',
179
+ workspaceRoot: isWorkspace ? cwd : undefined,
180
+ });
181
+ if (changedClaudeMd.length > 0) {
182
+ info('');
183
+ success(` Synced vendor notice in ${changedClaudeMd.length} CLAUDE.md file(s):`);
184
+ for (const changedPath of changedClaudeMd) {
185
+ info(` ${changedPath}`);
186
+ }
187
+ }
164
188
  info('');
165
189
  info(colors.bold('For a comprehensive update of everything, use:'));
166
190
  info('');
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.help = void 0;
15
16
  const path_1 = require("path");
16
17
  const ts_morph_1 = require("ts-morph");
17
18
  const framework_detection_1 = require("../../lib/framework-detection");
@@ -20,6 +21,46 @@ const object_1 = __importDefault(require("./object"));
20
21
  /**
21
22
  * Add property to module or object
22
23
  */
24
+ exports.help = {
25
+ aliases: ['ap'],
26
+ configuration: 'commands.server.addProp.*',
27
+ description: 'Add property to module/object',
28
+ name: 'addProp',
29
+ options: [
30
+ {
31
+ description: 'Target type to update',
32
+ flag: '--type',
33
+ required: true,
34
+ type: 'string',
35
+ values: ['Module', 'Object'],
36
+ },
37
+ { description: 'Name of the module or object to update', flag: '--element', required: true, type: 'string' },
38
+ {
39
+ default: false,
40
+ description: 'Skip lint fix after update',
41
+ flag: '--skipLint',
42
+ required: false,
43
+ type: 'boolean',
44
+ },
45
+ ],
46
+ propertyFlags: {
47
+ attributes: [
48
+ { description: 'Property name', name: 'name', type: 'string' },
49
+ {
50
+ description: 'Property type',
51
+ name: 'type',
52
+ type: 'string',
53
+ values: ['string', 'number', 'boolean', 'bigint', 'Date', 'ObjectId', 'Json'],
54
+ },
55
+ { description: 'Optional field', name: 'nullable', type: 'boolean' },
56
+ { description: 'Array of this type', name: 'array', type: 'boolean' },
57
+ { description: 'Enum type reference', name: 'enum', type: 'string' },
58
+ { description: 'Embedded object/schema reference', name: 'schema', type: 'string' },
59
+ { description: 'Reference module for ObjectId fields', name: 'reference', type: 'string' },
60
+ ],
61
+ pattern: '--prop-<attribute>-<index>',
62
+ },
63
+ };
23
64
  const NewCommand = {
24
65
  alias: ['ap'],
25
66
  description: 'Add property to module/object',
@@ -32,46 +73,7 @@ const NewCommand = {
32
73
  // Retrieve the tools we need
33
74
  const { config, filesystem, parameters, print: { divider, error, info, spin, success }, prompt: { ask, confirm }, server, strings: { pascalCase }, system, } = toolbox;
34
75
  // Handle --help-json flag
35
- if (toolbox.tools.helpJson({
36
- aliases: ['ap'],
37
- configuration: 'commands.server.addProp.*',
38
- description: 'Add property to module/object',
39
- name: 'addProp',
40
- options: [
41
- {
42
- description: 'Target type to update',
43
- flag: '--type',
44
- required: true,
45
- type: 'string',
46
- values: ['Module', 'Object'],
47
- },
48
- { description: 'Name of the module or object to update', flag: '--element', required: true, type: 'string' },
49
- {
50
- default: false,
51
- description: 'Skip lint fix after update',
52
- flag: '--skipLint',
53
- required: false,
54
- type: 'boolean',
55
- },
56
- ],
57
- propertyFlags: {
58
- attributes: [
59
- { description: 'Property name', name: 'name', type: 'string' },
60
- {
61
- description: 'Property type',
62
- name: 'type',
63
- type: 'string',
64
- values: ['string', 'number', 'boolean', 'bigint', 'Date', 'ObjectId', 'Json'],
65
- },
66
- { description: 'Optional field', name: 'nullable', type: 'boolean' },
67
- { description: 'Array of this type', name: 'array', type: 'boolean' },
68
- { description: 'Enum type reference', name: 'enum', type: 'string' },
69
- { description: 'Embedded object/schema reference', name: 'schema', type: 'string' },
70
- { description: 'Reference module for ObjectId fields', name: 'reference', type: 'string' },
71
- ],
72
- pattern: '--prop-<attribute>-<index>',
73
- },
74
- })) {
76
+ if (toolbox.tools.helpJson(exports.help)) {
75
77
  return;
76
78
  }
77
79
  const argProps = Object.keys(toolbox.parameters.options || {}).filter((key) => key.startsWith('prop'));
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.help = void 0;
12
13
  const framework_detection_1 = require("../../lib/framework-detection");
13
14
  /**
14
15
  * Convert an existing API project between npm mode and vendor mode.
@@ -17,6 +18,45 @@ const framework_detection_1 = require("../../lib/framework-detection");
17
18
  * lt server convert-mode --to vendor [--upstream-branch 11.24.2]
18
19
  * lt server convert-mode --to npm [--version 11.24.2]
19
20
  */
21
+ exports.help = {
22
+ description: 'Convert API project between npm and vendor framework modes',
23
+ name: 'convert-mode',
24
+ options: [
25
+ {
26
+ description: 'Target mode',
27
+ flag: '--to',
28
+ required: true,
29
+ type: 'string',
30
+ values: ['vendor', 'npm'],
31
+ },
32
+ {
33
+ description: 'Upstream branch/tag to vendor from (only with --to vendor)',
34
+ flag: '--upstream-branch',
35
+ required: false,
36
+ type: 'string',
37
+ },
38
+ {
39
+ description: 'nest-server version to install (only with --to npm, default: from VENDOR.md baseline)',
40
+ flag: '--version',
41
+ required: false,
42
+ type: 'string',
43
+ },
44
+ {
45
+ default: false,
46
+ description: 'Skip confirmation prompt',
47
+ flag: '--noConfirm',
48
+ required: false,
49
+ type: 'boolean',
50
+ },
51
+ {
52
+ default: false,
53
+ description: 'Show the resolved plan without making any changes',
54
+ flag: '--dry-run',
55
+ required: false,
56
+ type: 'boolean',
57
+ },
58
+ ],
59
+ };
20
60
  const ConvertModeCommand = {
21
61
  description: 'Convert API project between npm and vendor framework modes',
22
62
  hidden: false,
@@ -24,45 +64,7 @@ const ConvertModeCommand = {
24
64
  run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
25
65
  const { filesystem, parameters, print: { error, info, spin, success, warning }, prompt: { confirm }, server, } = toolbox;
26
66
  // 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
- })) {
67
+ if (toolbox.tools.helpJson(exports.help)) {
66
68
  return;
67
69
  }
68
70
  const targetMode = parameters.options.to;
@@ -9,10 +9,74 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.help = void 0;
12
13
  const workspace_integration_1 = require("../../lib/workspace-integration");
13
14
  /**
14
15
  * Create a new server
15
16
  */
17
+ exports.help = {
18
+ aliases: ['c'],
19
+ configuration: 'commands.server.create.*',
20
+ description: 'Create new server',
21
+ name: 'create',
22
+ options: [
23
+ { description: 'Server name', flag: '--name', required: true, type: 'string' },
24
+ {
25
+ description: 'API mode',
26
+ flag: '--api-mode',
27
+ required: false,
28
+ type: 'string',
29
+ values: ['Rest', 'GraphQL', 'Both'],
30
+ },
31
+ { description: 'Project description', flag: '--description', required: false, type: 'string' },
32
+ { description: 'Project author', flag: '--author', required: false, type: 'string' },
33
+ { description: 'Initialize git repository', flag: '--git', required: false, type: 'boolean' },
34
+ { description: 'Git branch to clone from', flag: '--branch', required: false, type: 'string' },
35
+ { description: 'Copy from local path instead of cloning', flag: '--copy', required: false, type: 'string' },
36
+ { description: 'Symlink to local path instead of cloning', flag: '--link', required: false, type: 'string' },
37
+ {
38
+ description: 'Backend framework consumption mode',
39
+ flag: '--framework-mode',
40
+ required: false,
41
+ type: 'string',
42
+ values: ['npm', 'vendor'],
43
+ },
44
+ {
45
+ description: 'Upstream nest-server branch/tag to vendor (with --framework-mode vendor)',
46
+ flag: '--framework-upstream-branch',
47
+ required: false,
48
+ type: 'string',
49
+ },
50
+ {
51
+ default: false,
52
+ description: 'Use experimental nest-base template (Bun + Prisma + Postgres)',
53
+ flag: '--next',
54
+ required: false,
55
+ type: 'boolean',
56
+ },
57
+ {
58
+ default: false,
59
+ description: 'Print resolved plan and exit without making any changes',
60
+ flag: '--dry-run',
61
+ required: false,
62
+ type: 'boolean',
63
+ },
64
+ {
65
+ default: false,
66
+ description: 'Override the workspace-detection abort under --noConfirm',
67
+ flag: '--force',
68
+ required: false,
69
+ type: 'boolean',
70
+ },
71
+ {
72
+ default: false,
73
+ description: 'Skip all interactive prompts',
74
+ flag: '--noConfirm',
75
+ required: false,
76
+ type: 'boolean',
77
+ },
78
+ ],
79
+ };
16
80
  const NewCommand = {
17
81
  alias: ['c'],
18
82
  description: 'Create new server',
@@ -23,69 +87,7 @@ const NewCommand = {
23
87
  // Retrieve the tools we need
24
88
  const { config, filesystem, git, helper, meta, parameters, print: { error, info, spin, success }, prompt: { ask, confirm }, server, strings: { kebabCase }, system, } = toolbox;
25
89
  // Handle --help-json flag
26
- if (toolbox.tools.helpJson({
27
- aliases: ['c'],
28
- configuration: 'commands.server.create.*',
29
- description: 'Create new server',
30
- name: 'create',
31
- options: [
32
- { description: 'Server name', flag: '--name', required: true, type: 'string' },
33
- {
34
- description: 'API mode',
35
- flag: '--api-mode',
36
- required: false,
37
- type: 'string',
38
- values: ['Rest', 'GraphQL', 'Both'],
39
- },
40
- { description: 'Project description', flag: '--description', required: false, type: 'string' },
41
- { description: 'Project author', flag: '--author', required: false, type: 'string' },
42
- { description: 'Initialize git repository', flag: '--git', required: false, type: 'boolean' },
43
- { description: 'Git branch to clone from', flag: '--branch', required: false, type: 'string' },
44
- { description: 'Copy from local path instead of cloning', flag: '--copy', required: false, type: 'string' },
45
- { description: 'Symlink to local path instead of cloning', flag: '--link', required: false, type: 'string' },
46
- {
47
- description: 'Backend framework consumption mode',
48
- flag: '--framework-mode',
49
- required: false,
50
- type: 'string',
51
- values: ['npm', 'vendor'],
52
- },
53
- {
54
- description: 'Upstream nest-server branch/tag to vendor (with --framework-mode vendor)',
55
- flag: '--framework-upstream-branch',
56
- required: false,
57
- type: 'string',
58
- },
59
- {
60
- default: false,
61
- description: 'Use experimental nest-base template (Bun + Prisma + Postgres)',
62
- flag: '--next',
63
- required: false,
64
- type: 'boolean',
65
- },
66
- {
67
- default: false,
68
- description: 'Print resolved plan and exit without making any changes',
69
- flag: '--dry-run',
70
- required: false,
71
- type: 'boolean',
72
- },
73
- {
74
- default: false,
75
- description: 'Override the workspace-detection abort under --noConfirm',
76
- flag: '--force',
77
- required: false,
78
- type: 'boolean',
79
- },
80
- {
81
- default: false,
82
- description: 'Skip all interactive prompts',
83
- flag: '--noConfirm',
84
- required: false,
85
- type: 'boolean',
86
- },
87
- ],
88
- })) {
90
+ if (toolbox.tools.helpJson(exports.help)) {
89
91
  return;
90
92
  }
91
93
  // Load configuration