@lenne.tech/cli 0.0.125 → 1.0.1

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 (46) hide show
  1. package/bin/lt +145 -14
  2. package/build/commands/claude/install-commands.js +332 -0
  3. package/build/commands/claude/install-skills.js +626 -0
  4. package/build/commands/config/config.js +25 -0
  5. package/build/commands/config/help.js +167 -0
  6. package/build/commands/config/init.js +143 -0
  7. package/build/commands/config/show.js +68 -0
  8. package/build/commands/server/add-property.js +163 -46
  9. package/build/commands/server/create.js +66 -4
  10. package/build/commands/server/module.js +133 -20
  11. package/build/commands/server/object.js +23 -15
  12. package/build/extensions/config.js +157 -0
  13. package/build/extensions/server.js +194 -63
  14. package/build/interfaces/lt-config.interface.js +3 -0
  15. package/build/templates/claude-commands/code-cleanup.md +82 -0
  16. package/build/templates/claude-commands/mr-description-clipboard.md +48 -0
  17. package/build/templates/claude-commands/mr-description.md +33 -0
  18. package/build/templates/claude-commands/sec-review.md +62 -0
  19. package/build/templates/claude-commands/skill-optimize.md +140 -0
  20. package/build/templates/claude-commands/test-generate.md +45 -0
  21. package/build/templates/claude-skills/lt-cli/SKILL.md +190 -259
  22. package/build/templates/claude-skills/lt-cli/examples.md +433 -203
  23. package/build/templates/claude-skills/lt-cli/reference.md +400 -226
  24. package/build/templates/claude-skills/nest-server-generator/SKILL.md +1891 -0
  25. package/build/templates/claude-skills/nest-server-generator/configuration.md +279 -0
  26. package/build/templates/claude-skills/nest-server-generator/declare-keyword-warning.md +124 -0
  27. package/build/templates/claude-skills/nest-server-generator/description-management.md +217 -0
  28. package/build/templates/claude-skills/nest-server-generator/examples.md +886 -0
  29. package/build/templates/claude-skills/nest-server-generator/quality-review.md +855 -0
  30. package/build/templates/claude-skills/nest-server-generator/reference.md +471 -0
  31. package/build/templates/claude-skills/nest-server-generator/security-rules.md +358 -0
  32. package/build/templates/claude-skills/story-tdd/SKILL.md +1173 -0
  33. package/build/templates/claude-skills/story-tdd/code-quality.md +266 -0
  34. package/build/templates/claude-skills/story-tdd/database-indexes.md +173 -0
  35. package/build/templates/claude-skills/story-tdd/examples.md +1332 -0
  36. package/build/templates/claude-skills/story-tdd/reference.md +1180 -0
  37. package/build/templates/claude-skills/story-tdd/security-review.md +299 -0
  38. package/build/templates/nest-server-module/inputs/template-create.input.ts.ejs +1 -3
  39. package/build/templates/nest-server-module/inputs/template.input.ts.ejs +1 -1
  40. package/build/templates/nest-server-module/template.controller.ts.ejs +24 -13
  41. package/build/templates/nest-server-module/template.model.ts.ejs +2 -2
  42. package/build/templates/nest-server-module/template.module.ts.ejs +4 -0
  43. package/build/templates/nest-server-module/template.service.ts.ejs +6 -6
  44. package/build/templates/nest-server-object/template.object.ts.ejs +2 -2
  45. package/package.json +13 -11
  46. package/build/commands/claude/install-skill.js +0 -93
@@ -0,0 +1,626 @@
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 os_1 = require("os");
13
+ const path_1 = require("path");
14
+ /**
15
+ * Skill-specific permissions mapping
16
+ */
17
+ const SKILL_PERMISSIONS = {
18
+ 'lt-cli': [
19
+ 'Bash(lt:*)',
20
+ ],
21
+ 'nest-server-generator': [
22
+ 'Bash(lt server:*)',
23
+ ],
24
+ 'story-tdd': [
25
+ 'Bash(npm test:*)',
26
+ 'Bash(npm run test:*)',
27
+ ],
28
+ };
29
+ /**
30
+ * Get skill descriptions from SKILL.md frontmatter
31
+ */
32
+ function getSkillDescription(skillDir, filesystem) {
33
+ const skillMdPath = (0, path_1.join)(skillDir, 'SKILL.md');
34
+ if (!filesystem.exists(skillMdPath)) {
35
+ return 'No description available';
36
+ }
37
+ const content = filesystem.read(skillMdPath);
38
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
39
+ if (!frontmatterMatch) {
40
+ return 'No description available';
41
+ }
42
+ const frontmatter = frontmatterMatch[1];
43
+ const descMatch = frontmatter.match(/description:\s*([^\n]+)/);
44
+ return descMatch ? descMatch[1].trim() : 'No description available';
45
+ }
46
+ /**
47
+ * Install a single skill
48
+ */
49
+ function installSingleSkill(skillName, cliRoot, filesystem, info, error) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ const templatesDir = (0, path_1.join)(cliRoot, 'templates', 'claude-skills', skillName);
52
+ // Check if templates exist
53
+ if (!filesystem.exists(templatesDir)) {
54
+ error(`Skill '${skillName}' not found in CLI installation.`);
55
+ info(`Expected location: ${templatesDir}`);
56
+ return { copiedCount: 0, skippedCount: 0, skippedFiles: [], success: false, updatedCount: 0 };
57
+ }
58
+ // Create ~/.claude/skills/<skillName> directory
59
+ const skillsDir = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'skills', skillName);
60
+ if (!filesystem.exists(skillsDir)) {
61
+ filesystem.dir(skillsDir);
62
+ }
63
+ // Copy all skill files with version checking
64
+ const skillFiles = ['SKILL.md', 'examples.md', 'reference.md'];
65
+ let copiedCount = 0;
66
+ let skippedCount = 0;
67
+ let updatedCount = 0;
68
+ const skippedFiles = [];
69
+ info(`\nInstalling skill: ${skillName}`);
70
+ for (const file of skillFiles) {
71
+ const sourcePath = (0, path_1.join)(templatesDir, file);
72
+ const targetPath = (0, path_1.join)(skillsDir, file);
73
+ if (!filesystem.exists(sourcePath)) {
74
+ info(` Warning: ${file} not found in templates, skipping...`);
75
+ continue;
76
+ }
77
+ const sourceContent = filesystem.read(sourcePath);
78
+ // Check if target file exists
79
+ if (filesystem.exists(targetPath)) {
80
+ const targetContent = filesystem.read(targetPath);
81
+ // Parse versions from both files
82
+ const sourceVersion = parseVersion(sourceContent);
83
+ const targetVersion = parseVersion(targetContent);
84
+ // If both have versions, compare them
85
+ if (sourceVersion && targetVersion) {
86
+ if (isVersionNewer(sourceVersion, targetVersion)) {
87
+ // Source is newer or equal, update
88
+ filesystem.write(targetPath, sourceContent);
89
+ updatedCount++;
90
+ copiedCount++;
91
+ info(` ✓ Updated ${file} (${targetVersion} → ${sourceVersion})`);
92
+ }
93
+ else {
94
+ // Target is newer, skip
95
+ skippedCount++;
96
+ const reason = `local version ${targetVersion} is newer than ${sourceVersion}`;
97
+ skippedFiles.push({ file: `${skillName}/${file}`, reason });
98
+ info(` ⊙ Skipped ${file} (${reason})`);
99
+ }
100
+ }
101
+ else if (sourceVersion && !targetVersion) {
102
+ // Source has version, target doesn't - update
103
+ filesystem.write(targetPath, sourceContent);
104
+ updatedCount++;
105
+ copiedCount++;
106
+ info(` ✓ Updated ${file} (no version → ${sourceVersion})`);
107
+ }
108
+ else {
109
+ // No version info, always update (backward compatibility)
110
+ filesystem.write(targetPath, sourceContent);
111
+ updatedCount++;
112
+ copiedCount++;
113
+ info(` ✓ Updated ${file} (no version control)`);
114
+ }
115
+ }
116
+ else {
117
+ // Target doesn't exist, create new
118
+ filesystem.write(targetPath, sourceContent);
119
+ copiedCount++;
120
+ const version = parseVersion(sourceContent);
121
+ info(` + Created ${file}${version ? ` (v${version})` : ''}`);
122
+ }
123
+ }
124
+ return { copiedCount, skippedCount, skippedFiles, success: true, updatedCount };
125
+ });
126
+ }
127
+ /**
128
+ * Compare semantic versions
129
+ * Returns true if sourceVersion >= targetVersion
130
+ */
131
+ function isVersionNewer(sourceVersion, targetVersion) {
132
+ const parseSemver = (version) => {
133
+ return version.split('.').map(n => parseInt(n, 10) || 0);
134
+ };
135
+ const source = parseSemver(sourceVersion);
136
+ const target = parseSemver(targetVersion);
137
+ // Compare major, minor, patch
138
+ for (let i = 0; i < 3; i++) {
139
+ if (source[i] > target[i]) {
140
+ return true;
141
+ }
142
+ if (source[i] < target[i]) {
143
+ return false;
144
+ }
145
+ }
146
+ // Versions are equal
147
+ return true;
148
+ }
149
+ /**
150
+ * Parse frontmatter from markdown file and extract version
151
+ */
152
+ function parseVersion(content) {
153
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
154
+ if (!frontmatterMatch) {
155
+ return null;
156
+ }
157
+ const frontmatter = frontmatterMatch[1];
158
+ const versionMatch = frontmatter.match(/version:\s*([^\n]+)/);
159
+ return versionMatch ? versionMatch[1].trim() : null;
160
+ }
161
+ /**
162
+ * Setup project detection hook for nest-server-generator
163
+ */
164
+ function setupProjectDetectionHook(filesystem, info, error, promptConfirm, skipInteractive) {
165
+ return __awaiter(this, void 0, void 0, function* () {
166
+ const globalSettingsPath = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'settings.json');
167
+ const cwd = filesystem.cwd();
168
+ // Detect if we're in a project with package.json
169
+ let packageJsonPath = null;
170
+ let searchDir = cwd;
171
+ // Search up to 3 levels for package.json
172
+ for (let i = 0; i < 3; i++) {
173
+ const testPath = (0, path_1.join)(searchDir, 'package.json');
174
+ if (filesystem.exists(testPath)) {
175
+ packageJsonPath = testPath;
176
+ break;
177
+ }
178
+ const parent = (0, path_1.join)(searchDir, '..');
179
+ if (parent === searchDir)
180
+ break; // Reached root
181
+ searchDir = parent;
182
+ }
183
+ // Determine installation scope
184
+ let scope = 'global';
185
+ let settingsPath = globalSettingsPath;
186
+ let projectRoot = null;
187
+ if (packageJsonPath) {
188
+ projectRoot = searchDir;
189
+ const projectSettingsPath = (0, path_1.join)(projectRoot, '.claude', 'settings.json');
190
+ // Ask where to install the hook
191
+ if (!skipInteractive) {
192
+ info('');
193
+ info(`Detected project at: ${projectRoot}`);
194
+ const choices = [
195
+ { name: 'Global (~/.claude/settings.json) - Available for all projects', value: 'global' },
196
+ { name: `Project (${projectRoot}/.claude/settings.json) - Only this project`, value: 'project' }
197
+ ];
198
+ const answer = yield promptConfirm({
199
+ choices: choices.map(c => c.name),
200
+ initial: 1, // Default to project
201
+ message: 'Where should the project detection hook be installed?',
202
+ name: 'scope',
203
+ type: 'select',
204
+ });
205
+ // Map the choice back to the value
206
+ scope = choices[answer.scope === 0 ? 0 : 1].value;
207
+ }
208
+ else {
209
+ // In non-interactive mode, prefer project if we found one
210
+ scope = 'project';
211
+ }
212
+ if (scope === 'project') {
213
+ settingsPath = projectSettingsPath;
214
+ // Ensure .claude directory exists
215
+ filesystem.dir((0, path_1.join)(projectRoot, '.claude'));
216
+ }
217
+ }
218
+ try {
219
+ // Read existing settings
220
+ let settings = {};
221
+ if (filesystem.exists(settingsPath)) {
222
+ const content = filesystem.read(settingsPath);
223
+ settings = JSON.parse(content);
224
+ }
225
+ // Ensure hooks array exists
226
+ if (!settings.hooks) {
227
+ settings.hooks = [];
228
+ }
229
+ // Check if hook already exists
230
+ const hookExists = settings.hooks.some((hook) => hook.event === 'user-prompt-submit' &&
231
+ hook.name === 'nest-server-detector');
232
+ if (hookExists) {
233
+ return {
234
+ added: false,
235
+ alreadyExists: true,
236
+ scope,
237
+ success: true,
238
+ };
239
+ }
240
+ // Create the hook configuration
241
+ const hook = {
242
+ command: `
243
+ # Detect @lenne.tech/nest-server in package.json and suggest using nest-server-generator skill
244
+ # Supports both single projects and monorepos
245
+
246
+ # Check if the prompt mentions NestJS-related tasks first
247
+ if ! echo "$PROMPT" | grep -qiE "(module|service|controller|resolver|model|object|nestjs|nest-server|lt server)"; then
248
+ # Not a NestJS-related prompt, skip
249
+ echo '{}'
250
+ exit 0
251
+ fi
252
+
253
+ # Function to check if package.json contains @lenne.tech/nest-server
254
+ check_package_json() {
255
+ local pkg_json="$1"
256
+ if [ -f "$pkg_json" ] && grep -q "@lenne\\.tech/nest-server" "$pkg_json"; then
257
+ return 0
258
+ fi
259
+ return 1
260
+ }
261
+
262
+ # First, check package.json in project root
263
+ if check_package_json "$CLAUDE_PROJECT_DIR/package.json"; then
264
+ cat << 'EOF'
265
+ {
266
+ "contextToAppend": "\\n\\n📦 Detected @lenne.tech/nest-server in this project. Consider using the nest-server-generator skill for this task."
267
+ }
268
+ EOF
269
+ exit 0
270
+ fi
271
+
272
+ # If not found in root, check common monorepo patterns
273
+ for pattern in "projects/*/package.json" "packages/*/package.json" "apps/*/package.json"; do
274
+ for pkg_json in $CLAUDE_PROJECT_DIR/$pattern; do
275
+ if check_package_json "$pkg_json"; then
276
+ cat << 'EOF'
277
+ {
278
+ "contextToAppend": "\\n\\n📦 Detected @lenne.tech/nest-server in this monorepo. Consider using the nest-server-generator skill for this task."
279
+ }
280
+ EOF
281
+ exit 0
282
+ fi
283
+ done
284
+ done
285
+
286
+ # No @lenne.tech/nest-server found
287
+ echo '{}'
288
+ exit 0
289
+ `.trim(),
290
+ description: 'Detects projects using @lenne.tech/nest-server and suggests using nest-server-generator skill',
291
+ event: 'user-prompt-submit',
292
+ name: 'nest-server-detector',
293
+ type: 'command',
294
+ };
295
+ // Add the hook
296
+ settings.hooks.push(hook);
297
+ // Write back settings
298
+ filesystem.write(settingsPath, JSON.stringify(settings, null, 2));
299
+ return {
300
+ added: true,
301
+ alreadyExists: false,
302
+ scope,
303
+ success: true,
304
+ };
305
+ }
306
+ catch (err) {
307
+ error(`Could not configure project detection hook: ${err.message}`);
308
+ return {
309
+ added: false,
310
+ alreadyExists: false,
311
+ error: true,
312
+ scope: 'none',
313
+ success: false,
314
+ };
315
+ }
316
+ });
317
+ }
318
+ /**
319
+ * Setup global permissions for installed skills
320
+ */
321
+ function setupSkillPermissions(skills, filesystem, error) {
322
+ return __awaiter(this, void 0, void 0, function* () {
323
+ const settingsPath = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'settings.json');
324
+ // Collect all requested permissions
325
+ const requestedPermissions = [];
326
+ skills.forEach(skill => {
327
+ const perms = SKILL_PERMISSIONS[skill];
328
+ if (perms) {
329
+ requestedPermissions.push(...perms);
330
+ }
331
+ });
332
+ if (requestedPermissions.length === 0) {
333
+ return { added: [], error: false, existing: [], requested: [], success: true };
334
+ }
335
+ try {
336
+ // Read existing settings
337
+ let settings = {};
338
+ if (filesystem.exists(settingsPath)) {
339
+ const content = filesystem.read(settingsPath);
340
+ settings = JSON.parse(content);
341
+ }
342
+ // Ensure permissions.allow exists
343
+ if (!settings.permissions) {
344
+ settings.permissions = {};
345
+ }
346
+ if (!settings.permissions.allow) {
347
+ settings.permissions.allow = [];
348
+ }
349
+ // Check which permissions are new vs existing
350
+ const existingPerms = new Set(settings.permissions.allow);
351
+ const added = [];
352
+ const existing = [];
353
+ requestedPermissions.forEach(perm => {
354
+ if (existingPerms.has(perm)) {
355
+ existing.push(perm);
356
+ }
357
+ else {
358
+ added.push(perm);
359
+ settings.permissions.allow.push(perm);
360
+ }
361
+ });
362
+ // Write back settings
363
+ filesystem.write(settingsPath, JSON.stringify(settings, null, 2));
364
+ return {
365
+ added,
366
+ existing,
367
+ requested: requestedPermissions,
368
+ success: true,
369
+ };
370
+ }
371
+ catch (err) {
372
+ error(`Could not configure permissions: ${err.message}`);
373
+ return {
374
+ added: [],
375
+ error: true,
376
+ existing: [],
377
+ requested: requestedPermissions,
378
+ success: false,
379
+ };
380
+ }
381
+ });
382
+ }
383
+ /**
384
+ * Install Claude Skills to ~/.claude/skills/
385
+ */
386
+ const NewCommand = {
387
+ alias: ['skills', 'is'],
388
+ description: 'Installs Claude Skills to ~/.claude/skills/ for Claude Code integration. Interactively select which skills to install. Use -y to skip interactive selection and install all skills.',
389
+ hidden: false,
390
+ name: 'install-skills',
391
+ run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
392
+ // Retrieve the tools we need
393
+ const { filesystem, parameters, print: { error, info, spin, success }, prompt, } = toolbox;
394
+ try {
395
+ // Get the CLI installation directory
396
+ const cliRoot = (0, path_1.join)(__dirname, '..', '..');
397
+ const claudeSkillsDir = (0, path_1.join)(cliRoot, 'templates', 'claude-skills');
398
+ // Check if claude-skills directory exists
399
+ if (!filesystem.exists(claudeSkillsDir)) {
400
+ error('Claude skills directory not found in CLI installation.');
401
+ info(`Expected location: ${claudeSkillsDir}`);
402
+ info('Please reinstall the CLI or report this issue.');
403
+ return;
404
+ }
405
+ // Get all available skills
406
+ const items = filesystem.list(claudeSkillsDir);
407
+ const availableSkills = items.filter(item => filesystem.isDirectory((0, path_1.join)(claudeSkillsDir, item)));
408
+ if (availableSkills.length === 0) {
409
+ error('No skills found in CLI installation.');
410
+ return;
411
+ }
412
+ let skillsToInstall = [];
413
+ const skipInteractive = parameters.options.y || parameters.options.yes || parameters.options['no-interactive'];
414
+ // Check if specific skills provided as parameters
415
+ if (parameters.first && parameters.first !== 'all') {
416
+ // Non-interactive mode: install specific skill(s)
417
+ const requestedSkills = parameters.array || [parameters.first];
418
+ // Validate requested skills
419
+ const invalidSkills = requestedSkills.filter(s => !availableSkills.includes(s));
420
+ if (invalidSkills.length > 0) {
421
+ error(`Invalid skill(s): ${invalidSkills.join(', ')}`);
422
+ info('');
423
+ info('Available skills:');
424
+ availableSkills.forEach(s => {
425
+ const desc = getSkillDescription((0, path_1.join)(claudeSkillsDir, s), filesystem);
426
+ info(` • ${s}`);
427
+ info(` ${desc}`);
428
+ });
429
+ return;
430
+ }
431
+ skillsToInstall = requestedSkills;
432
+ }
433
+ else if (parameters.first === 'all' || skipInteractive) {
434
+ // Install all skills without prompting
435
+ skillsToInstall = availableSkills;
436
+ if (skipInteractive) {
437
+ info('Installing all skills (non-interactive mode)...');
438
+ }
439
+ }
440
+ else {
441
+ // Interactive mode: ask for each skill individually
442
+ info('');
443
+ info('Available skills:');
444
+ info('');
445
+ // Show all available skills with descriptions
446
+ availableSkills.forEach(skill => {
447
+ const desc = getSkillDescription((0, path_1.join)(claudeSkillsDir, skill), filesystem);
448
+ info(` • ${skill}`);
449
+ info(` ${desc.substring(0, 100)}${desc.length > 100 ? '...' : ''}`);
450
+ info('');
451
+ });
452
+ // Ask if user wants to install all or select individually
453
+ const installAll = yield prompt.confirm('Install all skills?', true);
454
+ if (installAll) {
455
+ skillsToInstall = availableSkills;
456
+ }
457
+ else {
458
+ // Ask for each skill
459
+ info('');
460
+ info('Select which skills to install:');
461
+ info('');
462
+ for (const skill of availableSkills) {
463
+ const shouldInstall = yield prompt.confirm(`Install ${skill}?`, true);
464
+ if (shouldInstall) {
465
+ skillsToInstall.push(skill);
466
+ }
467
+ }
468
+ if (skillsToInstall.length === 0) {
469
+ info('No skills selected. Installation cancelled.');
470
+ return;
471
+ }
472
+ }
473
+ }
474
+ const installSpinner = spin(`Installing ${skillsToInstall.length} skill(s)...`);
475
+ let totalCopied = 0;
476
+ let totalSkipped = 0;
477
+ let totalUpdated = 0;
478
+ const allSkippedFiles = [];
479
+ // Install each skill
480
+ for (const skill of skillsToInstall) {
481
+ const result = yield installSingleSkill(skill, cliRoot, filesystem, info, error);
482
+ if (!result.success) {
483
+ continue;
484
+ }
485
+ totalCopied += result.copiedCount;
486
+ totalSkipped += result.skippedCount;
487
+ totalUpdated += result.updatedCount;
488
+ allSkippedFiles.push(...result.skippedFiles);
489
+ }
490
+ if (totalCopied === 0 && totalSkipped === 0) {
491
+ installSpinner.fail();
492
+ error('No skill files were found.');
493
+ return;
494
+ }
495
+ if (totalCopied === 0 && totalSkipped > 0) {
496
+ installSpinner.succeed('All selected skills are already up to date!');
497
+ info('');
498
+ info(`Skipped: ${totalSkipped} file(s) across ${skillsToInstall.length} skill(s)`);
499
+ info(`Location: ${(0, path_1.join)((0, os_1.homedir)(), '.claude', 'skills')}`);
500
+ return;
501
+ }
502
+ installSpinner.succeed(`Successfully installed ${skillsToInstall.length} skill(s) to ~/.claude/skills/`);
503
+ info('');
504
+ if (totalUpdated > 0 && totalSkipped > 0) {
505
+ success(`Updated ${totalUpdated} file(s), skipped ${totalSkipped} file(s)`);
506
+ }
507
+ else if (totalUpdated > 0) {
508
+ success(`Updated ${totalUpdated} file(s)`);
509
+ }
510
+ else {
511
+ success(`Created ${totalCopied} file(s)`);
512
+ }
513
+ info('');
514
+ info('Installed skills:');
515
+ skillsToInstall.forEach(s => {
516
+ const desc = getSkillDescription((0, path_1.join)(claudeSkillsDir, s), filesystem);
517
+ info(` • ${s}`);
518
+ info(` ${desc.substring(0, 100)}${desc.length > 100 ? '...' : ''}`);
519
+ });
520
+ info('');
521
+ info('These skills are now available in Claude Code!');
522
+ info('Claude will automatically use them when appropriate.');
523
+ info('');
524
+ info('Examples:');
525
+ if (skillsToInstall.includes('lt-cli')) {
526
+ info(' • "Create a User module with email and username"');
527
+ }
528
+ if (skillsToInstall.includes('nest-server-generator')) {
529
+ info(' • "Generate the complete server structure from this specification"');
530
+ }
531
+ info('');
532
+ info(`Location: ${(0, path_1.join)((0, os_1.homedir)(), '.claude', 'skills')}`);
533
+ if (totalSkipped > 0) {
534
+ info('');
535
+ info(`Note: ${totalSkipped} file(s) were skipped because your local versions are newer:`);
536
+ allSkippedFiles.forEach(({ file, reason }) => {
537
+ info(` • ${file} (${reason})`);
538
+ });
539
+ info('');
540
+ info('To force update, manually delete the files and run this command again.');
541
+ }
542
+ // Ask about setting up permissions
543
+ info('');
544
+ const setupPermissions = skipInteractive ? true : yield prompt.confirm('Set up global permissions for these skills? (Recommended - auto-approves skill-related commands)', true);
545
+ if (setupPermissions) {
546
+ const permissionsResult = yield setupSkillPermissions(skillsToInstall, filesystem, error);
547
+ if (permissionsResult.success) {
548
+ info('');
549
+ success('Permissions configured successfully!');
550
+ if (permissionsResult.added.length > 0) {
551
+ info('Added permissions:');
552
+ permissionsResult.added.forEach(perm => {
553
+ info(` • ${perm}`);
554
+ });
555
+ }
556
+ if (permissionsResult.existing.length > 0) {
557
+ info('Already configured:');
558
+ permissionsResult.existing.forEach(perm => {
559
+ info(` • ${perm}`);
560
+ });
561
+ }
562
+ info('');
563
+ info('Location: ~/.claude/settings.json');
564
+ }
565
+ else if (permissionsResult.error) {
566
+ info('');
567
+ info('⚠ Could not automatically configure permissions.');
568
+ info('You can manually add these to ~/.claude/settings.json:');
569
+ info('');
570
+ info(JSON.stringify({
571
+ permissions: {
572
+ allow: permissionsResult.requested
573
+ }
574
+ }, null, 2));
575
+ }
576
+ }
577
+ // Ask about setting up project detection hook for nest-server-generator
578
+ if (skillsToInstall.includes('nest-server-generator')) {
579
+ info('');
580
+ const setupHook = skipInteractive ? false : yield prompt.confirm('Set up automatic project detection for @lenne.tech/nest-server? (Recommended - suggests nest-server-generator skill when detected)', false);
581
+ if (setupHook) {
582
+ const hookResult = yield setupProjectDetectionHook(filesystem, info, error, prompt.ask, skipInteractive);
583
+ if (hookResult.success) {
584
+ if (hookResult.added) {
585
+ info('');
586
+ success('Project detection hook configured successfully!');
587
+ info('');
588
+ info(`Scope: ${hookResult.scope === 'global' ? 'Global (all projects)' : 'Project-specific'}`);
589
+ info('');
590
+ info('How it works:');
591
+ info(' • Detects @lenne.tech/nest-server in package.json');
592
+ info(' • Supports monorepos: searches projects/*, packages/*, apps/* directories');
593
+ info(' • Suggests using nest-server-generator skill for NestJS tasks');
594
+ info(' • Works from any directory in the project');
595
+ info('');
596
+ info(`Location: ${hookResult.scope === 'global' ? '~/.claude/settings.json' : '.claude/settings.json'}`);
597
+ }
598
+ else if (hookResult.alreadyExists) {
599
+ info('');
600
+ info('✓ Project detection hook already configured');
601
+ info(` Scope: ${hookResult.scope === 'global' ? 'Global' : 'Project-specific'}`);
602
+ }
603
+ }
604
+ else if (hookResult.error) {
605
+ info('');
606
+ info('⚠ Could not automatically configure project detection hook.');
607
+ info('You can manually add this hook to your settings.json');
608
+ }
609
+ }
610
+ }
611
+ }
612
+ catch (err) {
613
+ error(`Failed to install skill(s): ${err.message}`);
614
+ info('');
615
+ info('Troubleshooting:');
616
+ info(' • Ensure ~/.claude directory exists and is writable');
617
+ info(' • Check file permissions');
618
+ info(' • Try running with sudo if permission issues persist');
619
+ return;
620
+ }
621
+ // For tests
622
+ return `claude install-skills`;
623
+ }),
624
+ };
625
+ exports.default = NewCommand;
626
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbC1za2lsbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tbWFuZHMvY2xhdWRlL2luc3RhbGwtc2tpbGxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQ0EsMkJBQTZCO0FBQzdCLCtCQUE0QjtBQUk1Qjs7R0FFRztBQUNILE1BQU0saUJBQWlCLEdBQTZCO0lBQ2xELFFBQVEsRUFBRTtRQUNSLFlBQVk7S0FDYjtJQUNELHVCQUF1QixFQUFFO1FBQ3ZCLG1CQUFtQjtLQUNwQjtJQUNELFdBQVcsRUFBRTtRQUNYLGtCQUFrQjtRQUNsQixzQkFBc0I7S0FDdkI7Q0FDRixDQUFDO0FBRUY7O0dBRUc7QUFDSCxTQUFTLG1CQUFtQixDQUFDLFFBQWdCLEVBQUUsVUFBZTtJQUM1RCxNQUFNLFdBQVcsR0FBRyxJQUFBLFdBQUksRUFBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDL0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztRQUNwQyxPQUFPLDBCQUEwQixDQUFDO0lBQ3BDLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzdDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBQ2hFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3RCLE9BQU8sMEJBQTBCLENBQUM7SUFDcEMsQ0FBQztJQUVELE1BQU0sV0FBVyxHQUFHLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hDLE1BQU0sU0FBUyxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUUvRCxPQUFPLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FB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