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