@lenne.tech/cli 1.27.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.
Files changed (40) hide show
  1. package/build/cli.js +7 -1
  2. package/build/commands/dev/doctor.js +27 -1
  3. package/build/commands/dev/down.js +22 -10
  4. package/build/commands/dev/status.js +4 -3
  5. package/build/commands/dev/test.js +12 -4
  6. package/build/commands/dev/up.js +90 -50
  7. package/build/commands/frontend/angular.js +48 -46
  8. package/build/commands/frontend/convert-mode.js +41 -39
  9. package/build/commands/frontend/nuxt.js +49 -47
  10. package/build/commands/fullstack/add-api.js +34 -32
  11. package/build/commands/fullstack/add-app.js +25 -23
  12. package/build/commands/fullstack/convert-mode.js +85 -65
  13. package/build/commands/fullstack/init.js +12 -0
  14. package/build/commands/fullstack/update.js +24 -0
  15. package/build/commands/server/add-property.js +42 -40
  16. package/build/commands/server/convert-mode.js +41 -39
  17. package/build/commands/server/create.js +65 -63
  18. package/build/commands/server/module.js +56 -54
  19. package/build/commands/server/object.js +42 -40
  20. package/build/commands/server/permissions.js +60 -58
  21. package/build/commands/ticket/list.js +78 -0
  22. package/build/commands/ticket/start.js +141 -0
  23. package/build/commands/ticket/stop.js +166 -0
  24. package/build/commands/ticket/switch.js +70 -0
  25. package/build/commands/ticket/test.js +80 -0
  26. package/build/commands/ticket/ticket.js +36 -0
  27. package/build/commands/tools/crawl.js +92 -90
  28. package/build/extensions/frontend-helper.js +8 -37
  29. package/build/extensions/server.js +8 -38
  30. package/build/lib/command-help.js +161 -0
  31. package/build/lib/dev-identity.js +18 -0
  32. package/build/lib/dev-patches.js +1 -1
  33. package/build/lib/dev-project.js +14 -0
  34. package/build/lib/dev-state.js +96 -0
  35. package/build/lib/dev-test-session.js +55 -35
  36. package/build/lib/dev-ticket.js +343 -0
  37. package/build/lib/vendor-claude-md.js +227 -0
  38. package/docs/lt-dev-ticket-workflow.html +603 -0
  39. package/docs/lt-dev-ticket-workflow.pdf +0 -0
  40. package/package.json +32 -1
@@ -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 workspace_integration_1 = require("../../lib/workspace-integration");
13
14
  /**
14
15
  * Create a new nuxt workspace
@@ -18,6 +19,53 @@ const workspace_integration_1 = require("../../lib/workspace-integration");
18
19
  * a brand-new directory. Mirrors the same surface area as add-app where
19
20
  * applicable so behaviour is consistent across the four flows.
20
21
  */
22
+ exports.help = {
23
+ aliases: ['n'],
24
+ configuration: 'commands.frontend.nuxt.*',
25
+ description: 'Create a new Nuxt workspace from nuxt-base-starter',
26
+ name: 'nuxt',
27
+ options: [
28
+ { description: 'Workspace name', flag: '--name', required: false, type: 'string' },
29
+ { description: 'Branch of nuxt-base-starter to clone', flag: '--branch', required: false, type: 'string' },
30
+ { description: 'Copy from local template directory', flag: '--copy', required: false, type: 'string' },
31
+ { description: 'Symlink to local template directory', flag: '--link', required: false, type: 'string' },
32
+ {
33
+ description: 'Frontend framework consumption mode',
34
+ flag: '--frontend-framework-mode',
35
+ required: false,
36
+ type: 'string',
37
+ values: ['npm', 'vendor'],
38
+ },
39
+ {
40
+ default: false,
41
+ description: 'Default branch to nuxt-base-starter#next (auth basePath aligned with experimental --next API)',
42
+ flag: '--next',
43
+ required: false,
44
+ type: 'boolean',
45
+ },
46
+ {
47
+ default: false,
48
+ description: 'Print resolved plan and exit without making any changes',
49
+ flag: '--dry-run',
50
+ required: false,
51
+ type: 'boolean',
52
+ },
53
+ {
54
+ default: false,
55
+ description: 'Override the workspace-detection abort under --noConfirm',
56
+ flag: '--force',
57
+ required: false,
58
+ type: 'boolean',
59
+ },
60
+ {
61
+ default: false,
62
+ description: 'Skip all interactive prompts',
63
+ flag: '--noConfirm',
64
+ required: false,
65
+ type: 'boolean',
66
+ },
67
+ ],
68
+ };
21
69
  const NewCommand = {
22
70
  alias: ['n'],
23
71
  description: 'Creates a new nuxt workspace',
@@ -26,53 +74,7 @@ const NewCommand = {
26
74
  run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
27
75
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
28
76
  const { config, filesystem, frontendHelper, helper, parameters, print: { error, info, spin }, prompt: { ask, confirm }, strings: { kebabCase }, system, } = toolbox;
29
- if (toolbox.tools.helpJson({
30
- aliases: ['n'],
31
- configuration: 'commands.frontend.nuxt.*',
32
- description: 'Create a new Nuxt workspace from nuxt-base-starter',
33
- name: 'nuxt',
34
- options: [
35
- { description: 'Workspace name', flag: '--name', required: false, type: 'string' },
36
- { description: 'Branch of nuxt-base-starter to clone', flag: '--branch', required: false, type: 'string' },
37
- { description: 'Copy from local template directory', flag: '--copy', required: false, type: 'string' },
38
- { description: 'Symlink to local template directory', flag: '--link', required: false, type: 'string' },
39
- {
40
- description: 'Frontend framework consumption mode',
41
- flag: '--frontend-framework-mode',
42
- required: false,
43
- type: 'string',
44
- values: ['npm', 'vendor'],
45
- },
46
- {
47
- default: false,
48
- description: 'Default branch to nuxt-base-starter#next (auth basePath aligned with experimental --next API)',
49
- flag: '--next',
50
- required: false,
51
- type: 'boolean',
52
- },
53
- {
54
- default: false,
55
- description: 'Print resolved plan and exit without making any changes',
56
- flag: '--dry-run',
57
- required: false,
58
- type: 'boolean',
59
- },
60
- {
61
- default: false,
62
- description: 'Override the workspace-detection abort under --noConfirm',
63
- flag: '--force',
64
- required: false,
65
- type: 'boolean',
66
- },
67
- {
68
- default: false,
69
- description: 'Skip all interactive prompts',
70
- flag: '--noConfirm',
71
- required: false,
72
- type: 'boolean',
73
- },
74
- ],
75
- })) {
77
+ if (toolbox.tools.helpJson(exports.help)) {
76
78
  return;
77
79
  }
78
80
  // Load configuration. Nuxt-specific keys live under
@@ -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 hoist_workspace_pnpm_config_1 = require("../../lib/hoist-workspace-pnpm-config");
13
14
  const workspace_integration_1 = require("../../lib/workspace-integration");
14
15
  /**
@@ -20,6 +21,38 @@ const workspace_integration_1 = require("../../lib/workspace-integration");
20
21
  * `lt fullstack init` workflow on a fresh directory instead, or remove
21
22
  * the existing API first.
22
23
  */
24
+ exports.help = {
25
+ aliases: ['add-api'],
26
+ configuration: 'commands.fullstack.*',
27
+ description: 'Add a NestJS API to an existing fullstack workspace',
28
+ name: 'add-api',
29
+ options: [
30
+ { description: 'API mode', flag: '--api-mode', type: 'string', values: ['Rest', 'GraphQL', 'Both'] },
31
+ {
32
+ description: 'Framework consumption mode',
33
+ flag: '--framework-mode',
34
+ type: 'string',
35
+ values: ['npm', 'vendor'],
36
+ },
37
+ {
38
+ description: 'Branch/tag/commit of upstream nest-server (vendor mode)',
39
+ flag: '--framework-upstream-branch',
40
+ type: 'string',
41
+ },
42
+ { description: 'Branch of nest-server-starter to clone', flag: '--api-branch', type: 'string' },
43
+ { description: 'Path to local API template to copy from', flag: '--api-copy', type: 'string' },
44
+ { description: 'Path to local API template to symlink', flag: '--api-link', type: 'string' },
45
+ {
46
+ description: 'Use experimental nest-base template (Bun + Prisma + Postgres + Better-Auth)',
47
+ flag: '--next',
48
+ type: 'boolean',
49
+ },
50
+ { description: 'Workspace root (defaults to cwd)', flag: '--workspace-dir', type: 'string' },
51
+ { description: 'Skip install / format after API integration', flag: '--skip-install', type: 'boolean' },
52
+ { description: 'Print resolved plan and exit without disk changes', flag: '--dry-run', type: 'boolean' },
53
+ { description: 'Skip all interactive prompts', flag: '--noConfirm', type: 'boolean' },
54
+ ],
55
+ };
23
56
  const NewCommand = {
24
57
  alias: ['add-api'],
25
58
  description: 'Add API to fullstack workspace',
@@ -29,38 +62,7 @@ const NewCommand = {
29
62
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
30
63
  const { config, filesystem, git, parameters, patching, print: { error, info, spin, success, warning }, prompt: { ask }, server, system, } = toolbox;
31
64
  // Help-JSON support so AI agents can introspect the flags.
32
- if (toolbox.tools.helpJson({
33
- aliases: ['add-api'],
34
- configuration: 'commands.fullstack.*',
35
- description: 'Add a NestJS API to an existing fullstack workspace',
36
- name: 'add-api',
37
- options: [
38
- { description: 'API mode', flag: '--api-mode', type: 'string', values: ['Rest', 'GraphQL', 'Both'] },
39
- {
40
- description: 'Framework consumption mode',
41
- flag: '--framework-mode',
42
- type: 'string',
43
- values: ['npm', 'vendor'],
44
- },
45
- {
46
- description: 'Branch/tag/commit of upstream nest-server (vendor mode)',
47
- flag: '--framework-upstream-branch',
48
- type: 'string',
49
- },
50
- { description: 'Branch of nest-server-starter to clone', flag: '--api-branch', type: 'string' },
51
- { description: 'Path to local API template to copy from', flag: '--api-copy', type: 'string' },
52
- { description: 'Path to local API template to symlink', flag: '--api-link', type: 'string' },
53
- {
54
- description: 'Use experimental nest-base template (Bun + Prisma + Postgres + Better-Auth)',
55
- flag: '--next',
56
- type: 'boolean',
57
- },
58
- { description: 'Workspace root (defaults to cwd)', flag: '--workspace-dir', type: 'string' },
59
- { description: 'Skip install / format after API integration', flag: '--skip-install', type: 'boolean' },
60
- { description: 'Print resolved plan and exit without disk changes', flag: '--dry-run', type: 'boolean' },
61
- { description: 'Skip all interactive prompts', flag: '--noConfirm', type: 'boolean' },
62
- ],
63
- })) {
65
+ if (toolbox.tools.helpJson(exports.help)) {
64
66
  return;
65
67
  }
66
68
  const timer = system.startTimer();
@@ -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 hoist_workspace_pnpm_config_1 = require("../../lib/hoist-workspace-pnpm-config");
13
14
  const workspace_integration_1 = require("../../lib/workspace-integration");
14
15
  /**
@@ -19,6 +20,29 @@ const workspace_integration_1 = require("../../lib/workspace-integration");
19
20
  *
20
21
  * Refuses to run if `projects/app/` already exists.
21
22
  */
23
+ exports.help = {
24
+ aliases: ['add-app'],
25
+ configuration: 'commands.fullstack.*',
26
+ description: 'Add a frontend app to an existing fullstack workspace',
27
+ name: 'add-app',
28
+ options: [
29
+ { description: 'Frontend framework', flag: '--frontend', type: 'string', values: ['nuxt', 'angular'] },
30
+ {
31
+ description: 'Frontend framework consumption mode',
32
+ flag: '--frontend-framework-mode',
33
+ type: 'string',
34
+ values: ['npm', 'vendor'],
35
+ },
36
+ { description: 'Branch of the frontend starter to clone', flag: '--frontend-branch', type: 'string' },
37
+ { description: 'Path to local frontend template to copy from', flag: '--frontend-copy', type: 'string' },
38
+ { description: 'Path to local frontend template to symlink', flag: '--frontend-link', type: 'string' },
39
+ { description: 'Use experimental nuxt-base-starter `next` branch', flag: '--next', type: 'boolean' },
40
+ { description: 'Workspace root (defaults to cwd)', flag: '--workspace-dir', type: 'string' },
41
+ { description: 'Skip install / format after app integration', flag: '--skip-install', type: 'boolean' },
42
+ { description: 'Print resolved plan and exit without disk changes', flag: '--dry-run', type: 'boolean' },
43
+ { description: 'Skip all interactive prompts', flag: '--noConfirm', type: 'boolean' },
44
+ ],
45
+ };
22
46
  const NewCommand = {
23
47
  alias: ['add-app'],
24
48
  description: 'Add app to fullstack workspace',
@@ -27,29 +51,7 @@ const NewCommand = {
27
51
  run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
28
52
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
29
53
  const { config, filesystem, frontendHelper, git, parameters, print: { error, info, spin, success, warning }, prompt: { ask }, system, } = toolbox;
30
- if (toolbox.tools.helpJson({
31
- aliases: ['add-app'],
32
- configuration: 'commands.fullstack.*',
33
- description: 'Add a frontend app to an existing fullstack workspace',
34
- name: 'add-app',
35
- options: [
36
- { description: 'Frontend framework', flag: '--frontend', type: 'string', values: ['nuxt', 'angular'] },
37
- {
38
- description: 'Frontend framework consumption mode',
39
- flag: '--frontend-framework-mode',
40
- type: 'string',
41
- values: ['npm', 'vendor'],
42
- },
43
- { description: 'Branch of the frontend starter to clone', flag: '--frontend-branch', type: 'string' },
44
- { description: 'Path to local frontend template to copy from', flag: '--frontend-copy', type: 'string' },
45
- { description: 'Path to local frontend template to symlink', flag: '--frontend-link', type: 'string' },
46
- { description: 'Use experimental nuxt-base-starter `next` branch', flag: '--next', type: 'boolean' },
47
- { description: 'Workspace root (defaults to cwd)', flag: '--workspace-dir', type: 'string' },
48
- { description: 'Skip install / format after app integration', flag: '--skip-install', type: 'boolean' },
49
- { description: 'Print resolved plan and exit without disk changes', flag: '--dry-run', type: 'boolean' },
50
- { description: 'Skip all interactive prompts', flag: '--noConfirm', type: 'boolean' },
51
- ],
52
- })) {
54
+ if (toolbox.tools.helpJson(exports.help)) {
53
55
  return;
54
56
  }
55
57
  const timer = system.startTimer();
@@ -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'));