claude-code-templates 1.22.2 → 1.24.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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +71 -106
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.22.2",
3
+ "version": "1.24.1",
4
4
  "description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -1399,124 +1399,89 @@ async function installIndividualSkill(skillName, targetDir, options) {
1399
1399
  // Extract the actual skill name (last part of the path)
1400
1400
  const skillBaseName = skillName.includes('/') ? skillName.split('/').pop() : skillName;
1401
1401
 
1402
- // Skills always use SKILL.md as the main file (Anthropic standard)
1403
- // Format: skills/category/skill-name/SKILL.md
1404
- const githubUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/skills/${skillName}/SKILL.md`;
1405
-
1406
- console.log(chalk.gray(`📥 Downloading from GitHub (main branch)...`));
1407
-
1408
- const response = await fetch(githubUrl);
1409
- if (!response.ok) {
1410
- if (response.status === 404) {
1411
- console.log(chalk.red(`❌ Skill "${skillName}" not found`));
1412
- console.log(chalk.yellow('💡 Tip: Use format "category/skill-name" (e.g., creative-design/algorithmic-art)'));
1413
- console.log(chalk.yellow('Available categories: creative-design, development, document-processing, enterprise-communication'));
1414
- return false;
1415
- }
1416
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1417
- }
1418
-
1419
- const skillContent = await response.text();
1420
-
1421
- // Check if there are additional files to download (e.g., referenced .md files, scripts, reference)
1422
- const additionalFiles = {};
1402
+ // Use GitHub API to download ALL files and directories for the skill
1403
+ const githubApiUrl = `https://api.github.com/repos/davila7/claude-code-templates/contents/cli-tool/components/skills/${skillName}`;
1423
1404
 
1424
- // 1. Look for references to additional files like [FORMS.md](FORMS.md) or [reference](./reference/)
1425
- const referencePattern = /\[([A-Z_]+\.md)\]\(\1\)|\[.*?\]\(\.\/([a-z_]+)\/\)/g;
1426
- let match;
1405
+ console.log(chalk.gray(`📥 Downloading skill from GitHub (main branch)...`));
1427
1406
 
1428
- while ((match = referencePattern.exec(skillContent)) !== null) {
1429
- const referencedFile = match[1] || match[2];
1430
- const referencedUrl = githubUrl.replace('SKILL.md', referencedFile);
1407
+ const downloadedFiles = {};
1431
1408
 
1409
+ // Recursive function to download all files and directories
1410
+ async function downloadDirectory(apiUrl, relativePath = '') {
1432
1411
  try {
1433
- console.log(chalk.gray(`📥 Downloading referenced file: ${referencedFile}...`));
1434
- const refResponse = await fetch(referencedUrl);
1435
- if (refResponse.ok) {
1436
- const refContent = await refResponse.text();
1437
- additionalFiles[`.claude/skills/${skillBaseName}/${referencedFile}`] = {
1438
- content: refContent,
1439
- executable: false
1440
- };
1441
- console.log(chalk.green(`✓ Found referenced file: ${referencedFile}`));
1442
- }
1443
- } catch (error) {
1444
- // Referenced file is optional, continue if not found
1445
- console.log(chalk.gray(` (Referenced file ${referencedFile} not found, continuing...)`));
1446
- }
1447
- }
1448
-
1449
- // 2. Try to download common directories (scripts/, reference/) from GitHub API
1450
- const githubApiUrl = `https://api.github.com/repos/davila7/claude-code-templates/contents/cli-tool/components/skills/${skillName}`;
1412
+ const response = await fetch(apiUrl, {
1413
+ headers: {
1414
+ 'Accept': 'application/vnd.github.v3+json',
1415
+ 'User-Agent': 'claude-code-templates'
1416
+ }
1417
+ });
1451
1418
 
1452
- try {
1453
- const dirResponse = await fetch(githubApiUrl, {
1454
- headers: {
1455
- 'Accept': 'application/vnd.github.v3+json',
1456
- 'User-Agent': 'claude-code-templates'
1419
+ if (!response.ok) {
1420
+ if (response.status === 404) {
1421
+ console.log(chalk.red(`❌ Skill "${skillName}" not found`));
1422
+ console.log(chalk.yellow('💡 Tip: Use format "category/skill-name" (e.g., creative-design/algorithmic-art)'));
1423
+ console.log(chalk.yellow('Available categories: creative-design, development, document-processing, enterprise-communication'));
1424
+ return false;
1425
+ }
1426
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1457
1427
  }
1458
- });
1459
-
1460
- if (dirResponse.ok) {
1461
- const dirContents = await dirResponse.json();
1462
-
1463
- // Find directories (scripts, reference, templates)
1464
- for (const item of dirContents) {
1465
- if (item.type === 'dir' && ['scripts', 'reference', 'templates'].includes(item.name)) {
1466
- console.log(chalk.gray(`📂 Found directory: ${item.name}/`));
1467
-
1468
- // Fetch directory contents recursively
1469
- const subdirResponse = await fetch(item.url, {
1470
- headers: {
1471
- 'Accept': 'application/vnd.github.v3+json',
1472
- 'User-Agent': 'claude-code-templates'
1473
- }
1474
- });
1475
1428
 
1476
- if (subdirResponse.ok) {
1477
- const subdirContents = await subdirResponse.json();
1478
-
1479
- for (const file of subdirContents) {
1480
- if (file.type === 'file') {
1481
- try {
1482
- const fileResponse = await fetch(file.download_url);
1483
- if (fileResponse.ok) {
1484
- const fileContent = await fileResponse.text();
1485
- const isExecutable = file.name.endsWith('.py') || file.name.endsWith('.sh');
1486
-
1487
- additionalFiles[`.claude/skills/${skillBaseName}/${item.name}/${file.name}`] = {
1488
- content: fileContent,
1489
- executable: isExecutable
1490
- };
1491
- console.log(chalk.green(`✓ Downloaded: ${item.name}/${file.name}`));
1492
- }
1493
- } catch (err) {
1494
- console.log(chalk.gray(` (Could not download ${item.name}/${file.name})`));
1495
- }
1496
- }
1429
+ const contents = await response.json();
1430
+
1431
+ for (const item of contents) {
1432
+ const itemPath = relativePath ? `${relativePath}/${item.name}` : item.name;
1433
+
1434
+ if (item.type === 'file') {
1435
+ // Download file
1436
+ try {
1437
+ const fileResponse = await fetch(item.download_url);
1438
+ if (fileResponse.ok) {
1439
+ const fileContent = await fileResponse.text();
1440
+ const isExecutable = item.name.endsWith('.py') || item.name.endsWith('.sh');
1441
+
1442
+ const targetPath = `.claude/skills/${skillBaseName}/${itemPath}`;
1443
+ downloadedFiles[targetPath] = {
1444
+ content: fileContent,
1445
+ executable: isExecutable
1446
+ };
1447
+ console.log(chalk.green(`✓ Downloaded: ${itemPath}`));
1497
1448
  }
1449
+ } catch (err) {
1450
+ console.log(chalk.gray(` (Could not download ${itemPath})`));
1498
1451
  }
1452
+ } else if (item.type === 'dir') {
1453
+ // Recursively download directory contents
1454
+ console.log(chalk.gray(`📂 Downloading directory: ${itemPath}/`));
1455
+ await downloadDirectory(item.url, itemPath);
1499
1456
  }
1500
1457
  }
1458
+
1459
+ return true;
1460
+ } catch (error) {
1461
+ console.log(chalk.gray(` (Could not access GitHub API: ${error.message})`));
1462
+ return false;
1501
1463
  }
1502
- } catch (error) {
1503
- // GitHub API access optional, continue if not available
1504
- console.log(chalk.gray(` (Could not access GitHub API for directory listing)`));
1505
1464
  }
1506
1465
 
1507
- // Create .claude/skills/skill-name directory (Anthropic standard structure)
1508
- const skillsDir = path.join(targetDir, '.claude', 'skills');
1509
- const skillSubDir = path.join(skillsDir, skillBaseName);
1510
- await fs.ensureDir(skillSubDir);
1466
+ // Download all files from the skill directory
1467
+ const success = await downloadDirectory(githubApiUrl);
1468
+ if (!success) {
1469
+ return false;
1470
+ }
1511
1471
 
1512
- // Always use SKILL.md as filename (Anthropic standard)
1513
- const targetFile = path.join(skillSubDir, 'SKILL.md');
1472
+ // Check if SKILL.md was downloaded (required)
1473
+ const skillMdPath = `.claude/skills/${skillBaseName}/SKILL.md`;
1474
+ if (!downloadedFiles[skillMdPath]) {
1475
+ console.log(chalk.red(`❌ SKILL.md not found in skill directory`));
1476
+ return false;
1477
+ }
1514
1478
 
1515
- // Write the main skill file
1516
- await fs.writeFile(targetFile, skillContent, 'utf8');
1479
+ // Create .claude/skills/skill-name directory (Anthropic standard structure)
1480
+ const skillsDir = path.join(targetDir, '.claude', 'skills');
1481
+ await fs.ensureDir(skillsDir);
1517
1482
 
1518
- // Write any additional files
1519
- for (const [filePath, fileData] of Object.entries(additionalFiles)) {
1483
+ // Write all downloaded files
1484
+ for (const [filePath, fileData] of Object.entries(downloadedFiles)) {
1520
1485
  const fullPath = path.join(targetDir, filePath);
1521
1486
  await fs.ensureDir(path.dirname(fullPath));
1522
1487
  await fs.writeFile(fullPath, fileData.content, 'utf8');
@@ -1526,13 +1491,13 @@ async function installIndividualSkill(skillName, targetDir, options) {
1526
1491
  }
1527
1492
  }
1528
1493
 
1494
+ const targetFile = path.join(skillsDir, skillBaseName, 'SKILL.md');
1495
+
1529
1496
  if (!options.silent) {
1530
1497
  console.log(chalk.green(`✅ Skill "${skillName}" installed successfully!`));
1531
1498
  console.log(chalk.cyan(`📁 Installed to: ${path.relative(targetDir, targetFile)}`));
1532
- if (Object.keys(additionalFiles).length > 0) {
1533
- console.log(chalk.cyan(`📄 Additional files: ${Object.keys(additionalFiles).length}`));
1534
- }
1535
- console.log(chalk.cyan(`📦 Downloaded from: ${githubUrl}`));
1499
+ console.log(chalk.cyan(`📄 Total files downloaded: ${Object.keys(downloadedFiles).length}`));
1500
+ console.log(chalk.cyan(`📦 Downloaded from: ${githubApiUrl}`));
1536
1501
  }
1537
1502
 
1538
1503
  // Track successful skill installation
@@ -1540,7 +1505,7 @@ async function installIndividualSkill(skillName, targetDir, options) {
1540
1505
  installation_type: 'individual_skill',
1541
1506
  target_directory: path.relative(process.cwd(), targetDir),
1542
1507
  source: 'github_main',
1543
- has_additional_files: Object.keys(additionalFiles).length > 0
1508
+ total_files: Object.keys(downloadedFiles).length
1544
1509
  });
1545
1510
 
1546
1511
  return true;