claude-code-templates 1.14.2 → 1.15.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.
@@ -43,9 +43,8 @@ program
43
43
  .name('create-claude-config')
44
44
  .description('Setup Claude Code configurations for different programming languages')
45
45
  .version(require('../package.json').version)
46
- .option('-l, --language <language>', 'specify programming language (deprecated, use --template)')
47
- .option('-f, --framework <framework>', 'specify framework (deprecated, use --template)')
48
- .option('-t, --template <template>', 'specify template (e.g., common, javascript-typescript, python, ruby)')
46
+ .option('-l, --language <language>', 'specify programming language')
47
+ .option('-f, --framework <framework>', 'specify framework')
49
48
  .option('-d, --directory <directory>', 'target directory (default: current directory)')
50
49
  .option('-y, --yes', 'skip prompts and use defaults')
51
50
  .option('--dry-run', 'show what would be copied without actually copying')
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: api-security-audit
3
+ description: Use this agent when conducting security audits for REST APIs. Specializes in authentication vulnerabilities, authorization flaws, injection attacks, data exposure, and API security best practices. Examples: <example>Context: User needs to audit API security. user: 'I need to review my API endpoints for security vulnerabilities' assistant: 'I'll use the api-security-audit agent to perform a comprehensive security audit of your API endpoints' <commentary>Since the user needs API security assessment, use the api-security-audit agent for vulnerability analysis.</commentary></example> <example>Context: User has authentication issues. user: 'My API authentication seems vulnerable to attacks' assistant: 'Let me use the api-security-audit agent to analyze your authentication implementation and identify security weaknesses' <commentary>The user has specific authentication security concerns, so use the api-security-audit agent.</commentary></example>
4
+ color: red
5
+ ---
6
+
7
+ You are an API Security Audit specialist focusing on identifying, analyzing, and resolving security vulnerabilities in REST APIs. Your expertise covers authentication, authorization, data protection, and compliance with security standards.
8
+
9
+ Your core expertise areas:
10
+ - **Authentication Security**: JWT vulnerabilities, token management, session security
11
+ - **Authorization Flaws**: RBAC issues, privilege escalation, access control bypasses
12
+ - **Injection Attacks**: SQL injection, NoSQL injection, command injection prevention
13
+ - **Data Protection**: Sensitive data exposure, encryption, secure transmission
14
+ - **API Security Standards**: OWASP API Top 10, security headers, rate limiting
15
+ - **Compliance**: GDPR, HIPAA, PCI DSS requirements for APIs
16
+
17
+ ## When to Use This Agent
18
+
19
+ Use this agent for:
20
+ - Comprehensive API security audits
21
+ - Authentication and authorization reviews
22
+ - Vulnerability assessments and penetration testing
23
+ - Security compliance validation
24
+ - Incident response and remediation
25
+ - Security architecture reviews
26
+
27
+ ## Security Audit Checklist
28
+
29
+ ### Authentication & Authorization
30
+ ```javascript
31
+ // Secure JWT implementation
32
+ const jwt = require('jsonwebtoken');
33
+ const bcrypt = require('bcrypt');
34
+
35
+ class AuthService {
36
+ generateToken(user) {
37
+ return jwt.sign(
38
+ {
39
+ userId: user.id,
40
+ role: user.role,
41
+ permissions: user.permissions
42
+ },
43
+ process.env.JWT_SECRET,
44
+ {
45
+ expiresIn: '15m',
46
+ issuer: 'your-api',
47
+ audience: 'your-app'
48
+ }
49
+ );
50
+ }
51
+
52
+ verifyToken(token) {
53
+ try {
54
+ return jwt.verify(token, process.env.JWT_SECRET, {
55
+ issuer: 'your-api',
56
+ audience: 'your-app'
57
+ });
58
+ } catch (error) {
59
+ throw new Error('Invalid token');
60
+ }
61
+ }
62
+
63
+ async hashPassword(password) {
64
+ const saltRounds = 12;
65
+ return await bcrypt.hash(password, saltRounds);
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### Input Validation & Sanitization
71
+ ```javascript
72
+ const { body, validationResult } = require('express-validator');
73
+
74
+ const validateUserInput = [
75
+ body('email').isEmail().normalizeEmail(),
76
+ body('password').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/),
77
+ body('name').trim().escape().isLength({ min: 1, max: 100 }),
78
+
79
+ (req, res, next) => {
80
+ const errors = validationResult(req);
81
+ if (!errors.isEmpty()) {
82
+ return res.status(400).json({
83
+ error: 'Validation failed',
84
+ details: errors.array()
85
+ });
86
+ }
87
+ next();
88
+ }
89
+ ];
90
+ ```
91
+
92
+ Always provide specific, actionable security recommendations with code examples and remediation steps when conducting API security audits.
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: database-optimization
3
+ description: Use this agent when dealing with database performance issues. Specializes in query optimization, indexing strategies, schema design, connection pooling, and database monitoring. Examples: <example>Context: User has slow database queries. user: 'My database queries are taking too long to execute' assistant: 'I'll use the database-optimization agent to analyze and optimize your slow database queries' <commentary>Since the user has database performance issues, use the database-optimization agent for query analysis and optimization.</commentary></example> <example>Context: User needs indexing strategy. user: 'I need help designing indexes for better database performance' assistant: 'Let me use the database-optimization agent to design an optimal indexing strategy for your database schema' <commentary>The user needs indexing help, so use the database-optimization agent.</commentary></example>
4
+ color: blue
5
+ ---
6
+
7
+ You are a Database Optimization specialist focusing on improving database performance, query efficiency, and overall data access patterns. Your expertise covers SQL optimization, NoSQL performance tuning, and database architecture best practices.
8
+
9
+ Your core expertise areas:
10
+ - **Query Optimization**: SQL query tuning, execution plan analysis, join optimization
11
+ - **Indexing Strategies**: B-tree, hash, composite indexes, covering indexes
12
+ - **Schema Design**: Normalization, denormalization, partitioning strategies
13
+ - **Connection Management**: Connection pooling, transaction optimization
14
+ - **Performance Monitoring**: Query profiling, slow query analysis, metrics tracking
15
+ - **Database Architecture**: Replication, sharding, caching strategies
16
+
17
+ ## When to Use This Agent
18
+
19
+ Use this agent for:
20
+ - Slow query identification and optimization
21
+ - Database schema design and review
22
+ - Index strategy development
23
+ - Performance bottleneck analysis
24
+ - Connection pool configuration
25
+ - Database monitoring setup
26
+
27
+ ## Optimization Strategies
28
+
29
+ ### Query Optimization Examples
30
+ ```sql
31
+ -- Before: Inefficient query with N+1 problem
32
+ SELECT * FROM users WHERE id IN (
33
+ SELECT user_id FROM orders WHERE status = 'pending'
34
+ );
35
+
36
+ -- After: Optimized with proper JOIN
37
+ SELECT DISTINCT u.*
38
+ FROM users u
39
+ INNER JOIN orders o ON u.id = o.user_id
40
+ WHERE o.status = 'pending'
41
+ AND o.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY);
42
+
43
+ -- Add covering index for this query
44
+ CREATE INDEX idx_orders_status_created_userid
45
+ ON orders (status, created_at, user_id);
46
+ ```
47
+
48
+ ### Connection Pool Configuration
49
+ ```javascript
50
+ // Optimized connection pool setup
51
+ const mysql = require('mysql2/promise');
52
+
53
+ const pool = mysql.createPool({
54
+ host: process.env.DB_HOST,
55
+ user: process.env.DB_USER,
56
+ password: process.env.DB_PASSWORD,
57
+ database: process.env.DB_NAME,
58
+ waitForConnections: true,
59
+ connectionLimit: 10, // Adjust based on server capacity
60
+ queueLimit: 0,
61
+ acquireTimeout: 60000,
62
+ timeout: 60000,
63
+ reconnect: true,
64
+ // Enable prepared statements for better performance
65
+ namedPlaceholders: true
66
+ });
67
+
68
+ // Proper transaction handling
69
+ async function transferFunds(fromAccount, toAccount, amount) {
70
+ const connection = await pool.getConnection();
71
+ try {
72
+ await connection.beginTransaction();
73
+
74
+ await connection.execute(
75
+ 'UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ?',
76
+ [amount, fromAccount, amount]
77
+ );
78
+
79
+ await connection.execute(
80
+ 'UPDATE accounts SET balance = balance + ? WHERE id = ?',
81
+ [amount, toAccount]
82
+ );
83
+
84
+ await connection.commit();
85
+ } catch (error) {
86
+ await connection.rollback();
87
+ throw error;
88
+ } finally {
89
+ connection.release();
90
+ }
91
+ }
92
+ ```
93
+
94
+ Always provide specific performance improvements with measurable metrics and explain the reasoning behind optimization recommendations.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: react-performance-optimization
3
+ description: Use this agent when dealing with React performance issues. Specializes in identifying and fixing performance bottlenecks, bundle optimization, rendering optimization, and memory leaks. Examples: <example>Context: User has slow React application. user: 'My React app is loading slowly and feels sluggish during interactions' assistant: 'I'll use the react-performance-optimization agent to help identify and fix the performance bottlenecks in your React application' <commentary>Since the user has React performance issues, use the react-performance-optimization agent for performance analysis and optimization.</commentary></example> <example>Context: User needs help with bundle size optimization. user: 'My React app bundle is too large and taking too long to load' assistant: 'Let me use the react-performance-optimization agent to help optimize your bundle size and improve loading performance' <commentary>The user needs bundle optimization help, so use the react-performance-optimization agent.</commentary></example>
4
+ color: red
5
+ ---
6
+
7
+ You are a React Performance Optimization specialist focusing on identifying, analyzing, and resolving performance bottlenecks in React applications. Your expertise covers rendering optimization, bundle analysis, memory management, and Core Web Vitals.
8
+
9
+ Your core expertise areas:
10
+ - **Rendering Performance**: Component re-renders, reconciliation optimization
11
+ - **Bundle Optimization**: Code splitting, tree shaking, dynamic imports
12
+ - **Memory Management**: Memory leaks, cleanup patterns, resource management
13
+ - **Network Performance**: Lazy loading, prefetching, caching strategies
14
+ - **Core Web Vitals**: LCP, FID, CLS optimization for React apps
15
+ - **Profiling Tools**: React DevTools Profiler, Chrome DevTools, Lighthouse
16
+
17
+ ## When to Use This Agent
18
+
19
+ Use this agent for:
20
+ - Slow loading React applications
21
+ - Janky or unresponsive user interactions
22
+ - Large bundle sizes affecting load times
23
+ - Memory leaks or excessive memory usage
24
+ - Poor Core Web Vitals scores
25
+ - Performance regression analysis
26
+
27
+ ## Performance Optimization Strategies
28
+
29
+ ### React.memo for Component Memoization
30
+ ```javascript
31
+ const ExpensiveComponent = React.memo(({ data, onUpdate }) => {
32
+ const processedData = useMemo(() => {
33
+ return data.map(item => ({
34
+ ...item,
35
+ computed: heavyComputation(item)
36
+ }));
37
+ }, [data]);
38
+
39
+ return (
40
+ <div>
41
+ {processedData.map(item => (
42
+ <Item key={item.id} item={item} onUpdate={onUpdate} />
43
+ ))}
44
+ </div>
45
+ );
46
+ });
47
+ ```
48
+
49
+ ### Code Splitting with React.lazy
50
+ ```javascript
51
+ const Dashboard = lazy(() => import('./pages/Dashboard'));
52
+
53
+ const App = () => (
54
+ <Router>
55
+ <Suspense fallback={<LoadingSpinner />}>
56
+ <Routes>
57
+ <Route path="/dashboard" element={<Dashboard />} />
58
+ </Routes>
59
+ </Suspense>
60
+ </Router>
61
+ );
62
+ ```
63
+
64
+ Always provide specific, measurable solutions with before/after performance comparisons when helping with React performance optimization.
@@ -0,0 +1,53 @@
1
+ # File Analysis Tool
2
+
3
+ Perform comprehensive analysis of $ARGUMENTS to identify code quality issues, security vulnerabilities, and optimization opportunities.
4
+
5
+ ## Task
6
+
7
+ I'll analyze the specified file and provide detailed insights on:
8
+
9
+ 1. Code quality metrics and maintainability
10
+ 2. Security vulnerabilities and best practices
11
+ 3. Performance bottlenecks and optimization opportunities
12
+ 4. Dependency usage and potential issues
13
+ 5. TypeScript/JavaScript specific patterns and improvements
14
+ 6. Test coverage and missing tests
15
+
16
+ ## Process
17
+
18
+ I'll follow these steps:
19
+
20
+ 1. Read and parse the target file
21
+ 2. Analyze code structure and complexity
22
+ 3. Check for security vulnerabilities and anti-patterns
23
+ 4. Evaluate performance implications
24
+ 5. Review dependency usage and imports
25
+ 6. Provide actionable recommendations for improvement
26
+
27
+ ## Analysis Areas
28
+
29
+ ### Code Quality
30
+ - Cyclomatic complexity and maintainability metrics
31
+ - Code duplication and refactoring opportunities
32
+ - Naming conventions and code organization
33
+ - TypeScript type safety and best practices
34
+
35
+ ### Security Assessment
36
+ - Input validation and sanitization
37
+ - Authentication and authorization patterns
38
+ - Sensitive data exposure risks
39
+ - Common vulnerability patterns (XSS, injection, etc.)
40
+
41
+ ### Performance Review
42
+ - Bundle size impact and optimization opportunities
43
+ - Runtime performance bottlenecks
44
+ - Memory usage patterns
45
+ - Lazy loading and code splitting opportunities
46
+
47
+ ### Best Practices
48
+ - Framework-specific patterns (React, Vue, Angular)
49
+ - Modern JavaScript/TypeScript features usage
50
+ - Error handling and logging practices
51
+ - Testing patterns and coverage gaps
52
+
53
+ I'll provide specific, actionable recommendations tailored to your project's technology stack and architecture.
@@ -0,0 +1,68 @@
1
+ # Test Generator
2
+
3
+ Generate comprehensive test suite for $ARGUMENTS following project testing conventions and best practices.
4
+
5
+ ## Task
6
+
7
+ I'll analyze the target code and create complete test coverage including:
8
+
9
+ 1. Unit tests for individual functions and methods
10
+ 2. Integration tests for component interactions
11
+ 3. Edge case and error handling tests
12
+ 4. Mock implementations for external dependencies
13
+ 5. Test utilities and helpers as needed
14
+ 6. Performance and snapshot tests where appropriate
15
+
16
+ ## Process
17
+
18
+ I'll follow these steps:
19
+
20
+ 1. Analyze the target file/component structure
21
+ 2. Identify all testable functions, methods, and behaviors
22
+ 3. Examine existing test patterns in the project
23
+ 4. Create test files following project naming conventions
24
+ 5. Implement comprehensive test cases with proper setup/teardown
25
+ 6. Add necessary mocks and test utilities
26
+ 7. Verify test coverage and add missing test cases
27
+
28
+ ## Test Types
29
+
30
+ ### Unit Tests
31
+ - Individual function testing with various inputs
32
+ - Component rendering and prop handling
33
+ - State management and lifecycle methods
34
+ - Utility function edge cases and error conditions
35
+
36
+ ### Integration Tests
37
+ - Component interaction testing
38
+ - API integration with mocked responses
39
+ - Service layer integration
40
+ - End-to-end user workflows
41
+
42
+ ### Framework-Specific Tests
43
+ - **React**: Component testing with React Testing Library
44
+ - **Vue**: Component testing with Vue Test Utils
45
+ - **Angular**: Component and service testing with TestBed
46
+ - **Node.js**: API endpoint and middleware testing
47
+
48
+ ## Testing Best Practices
49
+
50
+ ### Test Structure
51
+ - Use descriptive test names that explain the behavior
52
+ - Follow AAA pattern (Arrange, Act, Assert)
53
+ - Group related tests with describe blocks
54
+ - Use proper setup and teardown for test isolation
55
+
56
+ ### Mock Strategy
57
+ - Mock external dependencies and API calls
58
+ - Use factories for test data generation
59
+ - Implement proper cleanup for async operations
60
+ - Mock timers and dates for deterministic tests
61
+
62
+ ### Coverage Goals
63
+ - Aim for 80%+ code coverage
64
+ - Focus on critical business logic paths
65
+ - Test both happy path and error scenarios
66
+ - Include boundary value testing
67
+
68
+ I'll adapt to your project's testing framework (Jest, Vitest, Cypress, etc.) and follow established patterns.
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "DeepGraph Next.js MCP": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "mcp-code-graph@latest",
8
+ "vercel/next.js"
9
+ ]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "DeepGraph React MCP": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "mcp-code-graph@latest",
8
+ "facebook/react"
9
+ ]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "DeepGraph TypeScript MCP": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "mcp-code-graph@latest",
8
+ "microsoft/TypeScript"
9
+ ]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "DeepGraph Vue MCP": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "mcp-code-graph@latest",
8
+ "vuejs/core"
9
+ ]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "filesystem": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "@modelcontextprotocol/server-filesystem",
8
+ "/path/to/allowed/files"
9
+ ]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "github": {
4
+ "command": "npx",
5
+ "args": ["-y", "@modelcontextprotocol/server-github"],
6
+ "env": {
7
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "memory": {
4
+ "command": "npx",
5
+ "args": ["-y", "@modelcontextprotocol/server-memory"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "mysql": {
4
+ "command": "uvx",
5
+ "args": ["mcp-server-mysql"],
6
+ "env": {
7
+ "MYSQL_CONNECTION_STRING": "mysql://user:password@localhost:3306/dbname"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "postgresql": {
4
+ "command": "npx",
5
+ "args": ["-y", "@modelcontextprotocol/server-postgres"],
6
+ "env": {
7
+ "POSTGRES_CONNECTION_STRING": "postgresql://user:password@localhost:5432/dbname"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "fetch": {
4
+ "command": "npx",
5
+ "args": ["-y", "@modelcontextprotocol/server-fetch"]
6
+ }
7
+ }
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.14.2",
3
+ "version": "1.15.0",
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": {
@@ -86,6 +86,7 @@
86
86
  "bin/",
87
87
  "src/",
88
88
  "templates/",
89
+ "components/",
89
90
  "README.md"
90
91
  ],
91
92
  "devDependencies": {
@@ -4,152 +4,6 @@ const chalk = require('chalk');
4
4
  const inquirer = require('inquirer');
5
5
  const { getHooksForLanguage, filterHooksBySelection, getMCPsForLanguage, filterMCPsBySelection } = require('./hook-scanner');
6
6
 
7
- // GitHub configuration for downloading templates
8
- const GITHUB_CONFIG = {
9
- owner: 'davila7',
10
- repo: 'claude-code-templates',
11
- branch: 'main',
12
- templatesPath: 'cli-tool/templates'
13
- };
14
-
15
- // Cache for downloaded files to avoid repeated downloads
16
- const downloadCache = new Map();
17
-
18
- async function downloadFileFromGitHub(filePath) {
19
- // Check cache first
20
- if (downloadCache.has(filePath)) {
21
- return downloadCache.get(filePath);
22
- }
23
-
24
- const githubUrl = `https://raw.githubusercontent.com/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/${GITHUB_CONFIG.branch}/${GITHUB_CONFIG.templatesPath}/${filePath}`;
25
-
26
- try {
27
- const response = await fetch(githubUrl);
28
- if (!response.ok) {
29
- throw new Error(`Failed to download ${filePath}: ${response.status} ${response.statusText}`);
30
- }
31
-
32
- const content = await response.text();
33
- downloadCache.set(filePath, content);
34
- return content;
35
- } catch (error) {
36
- console.error(chalk.red(`❌ Error downloading ${filePath} from GitHub:`), error.message);
37
- throw error;
38
- }
39
- }
40
-
41
- async function downloadDirectoryFromGitHub(dirPath) {
42
- // For directories, we need to get the list of files first
43
- // GitHub API endpoint to get directory contents
44
- const apiUrl = `https://api.github.com/repos/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/contents/${GITHUB_CONFIG.templatesPath}/${dirPath}?ref=${GITHUB_CONFIG.branch}`;
45
-
46
- try {
47
- const response = await fetch(apiUrl);
48
- if (!response.ok) {
49
- throw new Error(`Failed to get directory listing for ${dirPath}: ${response.status} ${response.statusText}`);
50
- }
51
-
52
- const items = await response.json();
53
- const files = {};
54
-
55
- for (const item of items) {
56
- if (item.type === 'file') {
57
- const relativePath = path.relative(GITHUB_CONFIG.templatesPath, item.path);
58
- const content = await downloadFileFromGitHub(relativePath);
59
- files[item.name] = content;
60
- }
61
- }
62
-
63
- return files;
64
- } catch (error) {
65
- console.error(chalk.red(`❌ Error downloading directory ${dirPath} from GitHub:`), error.message);
66
- throw error;
67
- }
68
- }
69
-
70
- // Helper functions for processing downloaded content
71
- async function processSettingsFileFromContent(settingsContent, destPath, templateConfig) {
72
- const settings = JSON.parse(settingsContent);
73
-
74
- // Filter hooks based on selection
75
- if (templateConfig.selectedHooks && settings.hooks) {
76
- settings.hooks = filterHooksBySelection(settings.hooks, templateConfig.selectedHooks);
77
- }
78
-
79
- const destDir = path.dirname(destPath);
80
- await fs.ensureDir(destDir);
81
- await fs.writeJson(destPath, settings, { spaces: 2 });
82
- }
83
-
84
- async function mergeSettingsFileFromContent(settingsContent, destPath, templateConfig) {
85
- const newSettings = JSON.parse(settingsContent);
86
- let existingSettings = {};
87
-
88
- if (await fs.pathExists(destPath)) {
89
- existingSettings = await fs.readJson(destPath);
90
- }
91
-
92
- // Filter hooks based on selection
93
- if (templateConfig.selectedHooks && newSettings.hooks) {
94
- newSettings.hooks = filterHooksBySelection(newSettings.hooks, templateConfig.selectedHooks);
95
- }
96
-
97
- // Merge settings
98
- const mergedSettings = {
99
- ...existingSettings,
100
- ...newSettings,
101
- hooks: {
102
- ...existingSettings.hooks,
103
- ...newSettings.hooks
104
- }
105
- };
106
-
107
- const destDir = path.dirname(destPath);
108
- await fs.ensureDir(destDir);
109
- await fs.writeJson(destPath, mergedSettings, { spaces: 2 });
110
- }
111
-
112
- async function processMCPFileFromContent(mcpContent, destPath, templateConfig) {
113
- const mcpConfig = JSON.parse(mcpContent);
114
-
115
- // Filter MCPs based on selection
116
- if (templateConfig.selectedMCPs && mcpConfig.mcpServers) {
117
- mcpConfig.mcpServers = filterMCPsBySelection(mcpConfig.mcpServers, templateConfig.selectedMCPs);
118
- }
119
-
120
- const destDir = path.dirname(destPath);
121
- await fs.ensureDir(destDir);
122
- await fs.writeJson(destPath, mcpConfig, { spaces: 2 });
123
- }
124
-
125
- async function mergeMCPFileFromContent(mcpContent, destPath, templateConfig) {
126
- const newMcpConfig = JSON.parse(mcpContent);
127
- let existingMcpConfig = {};
128
-
129
- if (await fs.pathExists(destPath)) {
130
- existingMcpConfig = await fs.readJson(destPath);
131
- }
132
-
133
- // Filter MCPs based on selection
134
- if (templateConfig.selectedMCPs && newMcpConfig.mcpServers) {
135
- newMcpConfig.mcpServers = filterMCPsBySelection(newMcpConfig.mcpServers, templateConfig.selectedMCPs);
136
- }
137
-
138
- // Merge MCP configurations
139
- const mergedMcpConfig = {
140
- ...existingMcpConfig,
141
- ...newMcpConfig,
142
- mcpServers: {
143
- ...existingMcpConfig.mcpServers,
144
- ...newMcpConfig.mcpServers
145
- }
146
- };
147
-
148
- const destDir = path.dirname(destPath);
149
- await fs.ensureDir(destDir);
150
- await fs.writeJson(destPath, mergedMcpConfig, { spaces: 2 });
151
- }
152
-
153
7
  async function checkExistingFiles(targetDir, templateConfig) {
154
8
  const existingFiles = [];
155
9
 
@@ -232,7 +86,7 @@ async function createBackups(existingFiles, targetDir) {
232
86
  }
233
87
 
234
88
  async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
235
- console.log(chalk.gray(`📥 Downloading templates from GitHub (${GITHUB_CONFIG.branch} branch)...`));
89
+ const templateDir = path.join(__dirname, '../templates');
236
90
 
237
91
  // Check for existing files and get user preference
238
92
  const existingFiles = await checkExistingFiles(targetDir, templateConfig);
@@ -260,6 +114,7 @@ async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
260
114
 
261
115
  // Copy base files and framework-specific files
262
116
  for (const file of templateConfig.files) {
117
+ const sourcePath = path.join(templateDir, file.source);
263
118
  const destPath = path.join(targetDir, file.destination);
264
119
 
265
120
  try {
@@ -268,115 +123,94 @@ async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
268
123
  // This is a framework-specific commands directory - merge with existing commands
269
124
  await fs.ensureDir(destPath);
270
125
 
271
- // Download framework-specific commands from GitHub
272
- const frameworkFiles = await downloadDirectoryFromGitHub(file.source);
273
- for (const [frameworkFileName, content] of Object.entries(frameworkFiles)) {
274
- const destFile = path.join(destPath, frameworkFileName);
126
+ // Copy framework-specific commands to the commands directory
127
+ const frameworkFiles = await fs.readdir(sourcePath);
128
+ for (const frameworkFile of frameworkFiles) {
129
+ const srcFile = path.join(sourcePath, frameworkFile);
130
+ const destFile = path.join(destPath, frameworkFile);
275
131
 
276
132
  // In merge mode, skip if file already exists
277
133
  if (userAction === 'merge' && await fs.pathExists(destFile)) {
278
- console.log(chalk.blue(`⏭️ Skipped ${frameworkFileName} (already exists)`));
134
+ console.log(chalk.blue(`⏭️ Skipped ${frameworkFile} (already exists)`));
279
135
  continue;
280
136
  }
281
137
 
282
- await fs.writeFile(destFile, content, 'utf8');
138
+ await fs.copy(srcFile, destFile, { overwrite: shouldOverwrite });
283
139
  }
284
140
 
285
- console.log(chalk.green(`✓ Downloaded framework commands ${file.source} → ${file.destination}`));
141
+ console.log(chalk.green(`✓ Copied framework commands ${file.source} → ${file.destination}`));
286
142
  } else if (file.source.includes('.claude') && !file.source.includes('examples/')) {
287
- // This is base .claude directory - download it but handle commands specially
288
- await fs.ensureDir(destPath);
143
+ // This is base .claude directory - copy it but handle commands specially
144
+ await fs.copy(sourcePath, destPath, {
145
+ overwrite: shouldOverwrite,
146
+ filter: (src) => {
147
+ // Skip the commands directory itself - we'll handle it separately
148
+ return !src.endsWith('.claude/commands');
149
+ }
150
+ });
289
151
 
290
- // Download base .claude directory structure from GitHub
291
- try {
292
- const baseClaudeFiles = await downloadDirectoryFromGitHub(file.source);
152
+ // Now handle base commands specifically
153
+ const baseCommandsPath = path.join(sourcePath, 'commands');
154
+ const destCommandsPath = path.join(destPath, 'commands');
155
+
156
+ if (await fs.pathExists(baseCommandsPath)) {
157
+ await fs.ensureDir(destCommandsPath);
158
+
159
+ // Copy base commands, but exclude framework-specific ones that were moved
160
+ const baseCommands = await fs.readdir(baseCommandsPath);
161
+ const excludeCommands = ['react-component.md', 'route.md', 'api-endpoint.md']; // Commands moved to framework dirs
293
162
 
294
- // Write non-command files first
295
- for (const [fileName, content] of Object.entries(baseClaudeFiles)) {
296
- if (fileName !== 'commands') { // Skip commands directory, handle separately
297
- const destFile = path.join(destPath, fileName);
163
+ for (const baseCommand of baseCommands) {
164
+ if (!excludeCommands.includes(baseCommand)) {
165
+ const srcFile = path.join(baseCommandsPath, baseCommand);
166
+ const destFile = path.join(destCommandsPath, baseCommand);
298
167
 
299
168
  // In merge mode, skip if file already exists
300
169
  if (userAction === 'merge' && await fs.pathExists(destFile)) {
301
- console.log(chalk.blue(`⏭️ Skipped ${fileName} (already exists)`));
170
+ console.log(chalk.blue(`⏭️ Skipped ${baseCommand} (already exists)`));
302
171
  continue;
303
172
  }
304
173
 
305
- await fs.writeFile(destFile, content, 'utf8');
174
+ await fs.copy(srcFile, destFile, { overwrite: shouldOverwrite });
306
175
  }
307
176
  }
308
-
309
- // Now handle base commands specifically
310
- const destCommandsPath = path.join(destPath, 'commands');
311
- await fs.ensureDir(destCommandsPath);
312
-
313
- // Download base commands from GitHub
314
- const baseCommandsDir = `${file.source}/commands`;
315
- try {
316
- const baseCommands = await downloadDirectoryFromGitHub(baseCommandsDir);
317
- const excludeCommands = ['react-component.md', 'route.md', 'api-endpoint.md']; // Commands moved to framework dirs
318
-
319
- for (const [baseCommandName, commandContent] of Object.entries(baseCommands)) {
320
- if (!excludeCommands.includes(baseCommandName)) {
321
- const destFile = path.join(destCommandsPath, baseCommandName);
322
-
323
- // In merge mode, skip if file already exists
324
- if (userAction === 'merge' && await fs.pathExists(destFile)) {
325
- console.log(chalk.blue(`⏭️ Skipped ${baseCommandName} (already exists)`));
326
- continue;
327
- }
328
-
329
- await fs.writeFile(destFile, commandContent, 'utf8');
330
- }
331
- }
332
- } catch (error) {
333
- // Commands directory might not exist for some templates, that's ok
334
- console.log(chalk.yellow(`⚠️ No commands directory found for ${baseCommandsDir}`));
335
- }
336
-
337
- } catch (error) {
338
- console.error(chalk.red(`❌ Error downloading .claude directory: ${error.message}`));
339
- throw error;
340
177
  }
341
178
 
342
- console.log(chalk.green(`✓ Downloaded base configuration and commands ${file.source} → ${file.destination}`));
179
+ console.log(chalk.green(`✓ Copied base configuration and commands ${file.source} → ${file.destination}`));
343
180
  } else if (file.source.includes('settings.json') && templateConfig.selectedHooks) {
344
- // Download and process settings.json with hooks
345
- const settingsContent = await downloadFileFromGitHub(file.source);
346
-
347
181
  // In merge mode, merge settings instead of overwriting
348
182
  if (userAction === 'merge') {
349
- await mergeSettingsFileFromContent(settingsContent, destPath, templateConfig);
183
+ await mergeSettingsFile(sourcePath, destPath, templateConfig);
350
184
  console.log(chalk.green(`✓ Merged ${file.source} → ${file.destination} (with selected hooks)`));
351
185
  } else {
352
- await processSettingsFileFromContent(settingsContent, destPath, templateConfig);
353
- console.log(chalk.green(`✓ Downloaded ${file.source} → ${file.destination} (with selected hooks)`));
186
+ await processSettingsFile(sourcePath, destPath, templateConfig);
187
+ console.log(chalk.green(`✓ Copied ${file.source} → ${file.destination} (with selected hooks)`));
354
188
  }
355
189
  } else if (file.source.includes('.mcp.json') && templateConfig.selectedMCPs) {
356
- // Download and process MCP config with selected MCPs
357
- const mcpContent = await downloadFileFromGitHub(file.source);
358
-
359
190
  // In merge mode, merge MCP config instead of overwriting
360
191
  if (userAction === 'merge') {
361
- await mergeMCPFileFromContent(mcpContent, destPath, templateConfig);
192
+ await mergeMCPFile(sourcePath, destPath, templateConfig);
362
193
  console.log(chalk.green(`✓ Merged ${file.source} → ${file.destination} (with selected MCPs)`));
363
194
  } else {
364
- await processMCPFileFromContent(mcpContent, destPath, templateConfig);
365
- console.log(chalk.green(`✓ Downloaded ${file.source} → ${file.destination} (with selected MCPs)`));
195
+ await processMCPFile(sourcePath, destPath, templateConfig);
196
+ console.log(chalk.green(`✓ Copied ${file.source} → ${file.destination} (with selected MCPs)`));
366
197
  }
367
198
  } else {
368
- // Download regular files (CLAUDE.md, etc.)
199
+ // Copy regular files (CLAUDE.md, etc.)
369
200
  // In merge mode, skip if file already exists
370
201
  if (userAction === 'merge' && await fs.pathExists(destPath)) {
371
202
  console.log(chalk.blue(`⏭️ Skipped ${file.destination} (already exists)`));
372
203
  continue;
373
204
  }
374
205
 
375
- const fileContent = await downloadFileFromGitHub(file.source);
376
- const destDir = path.dirname(destPath);
377
- await fs.ensureDir(destDir);
378
- await fs.writeFile(destPath, fileContent, 'utf8');
379
- console.log(chalk.green(`✓ Downloaded ${file.source} → ${file.destination}`));
206
+ await fs.copy(sourcePath, destPath, {
207
+ overwrite: shouldOverwrite,
208
+ filter: (src) => {
209
+ // Skip commands directory during regular copy - we handle them above
210
+ return !src.includes('.claude/commands');
211
+ }
212
+ });
213
+ console.log(chalk.green(`✓ Copied ${file.source} → ${file.destination}`));
380
214
  }
381
215
  } catch (error) {
382
216
  console.error(chalk.red(`✗ Failed to copy ${file.source}:`), error.message);
@@ -384,8 +218,38 @@ async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
384
218
  }
385
219
  }
386
220
 
387
- console.log(chalk.cyan(`📦 All templates downloaded from: https://github.com/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/tree/${GITHUB_CONFIG.branch}/${GITHUB_CONFIG.templatesPath}`));
388
221
  return true; // Indicate successful completion
222
+
223
+ // Copy selected commands individually
224
+ if (templateConfig.selectedCommands && templateConfig.selectedCommands.length > 0) {
225
+ const commandsDir = path.join(targetDir, '.claude', 'commands');
226
+ await fs.ensureDir(commandsDir);
227
+
228
+ for (const command of templateConfig.selectedCommands) {
229
+ try {
230
+ const commandFileName = `${command.name}.md`;
231
+ const destPath = path.join(commandsDir, commandFileName);
232
+
233
+ await fs.copy(command.filePath, destPath);
234
+ console.log(chalk.green(`✓ Added command: ${command.displayName}`));
235
+ } catch (error) {
236
+ console.error(chalk.red(`✗ Failed to copy command ${command.name}:`), error.message);
237
+ // Don't throw - continue with other commands
238
+ }
239
+ }
240
+
241
+ console.log(chalk.cyan(`📋 Installed ${templateConfig.selectedCommands.length} commands`));
242
+ }
243
+
244
+ // Report hook selection
245
+ if (templateConfig.selectedHooks && templateConfig.selectedHooks.length > 0) {
246
+ console.log(chalk.magenta(`🔧 Installed ${templateConfig.selectedHooks.length} automation hooks`));
247
+ }
248
+
249
+ // Report MCP selection
250
+ if (templateConfig.selectedMCPs && templateConfig.selectedMCPs.length > 0) {
251
+ console.log(chalk.blue(`🔧 Installed ${templateConfig.selectedMCPs.length} MCP`));
252
+ }
389
253
  }
390
254
 
391
255
  async function runPostInstallationValidation(targetDir, templateConfig) {
package/src/index.js CHANGED
@@ -175,8 +175,8 @@ async function createClaudeConfig(options = {}) {
175
175
 
176
176
  let config;
177
177
  if (options.yes) {
178
- // Use defaults - prioritize --template over --language for backward compatibility
179
- const selectedLanguage = options.template || options.language || projectInfo.detectedLanguage || 'common';
178
+ // Use defaults
179
+ const selectedLanguage = options.language || projectInfo.detectedLanguage || 'common';
180
180
 
181
181
  // Check if selected language is coming soon
182
182
  if (selectedLanguage && TEMPLATES_CONFIG[selectedLanguage] && TEMPLATES_CONFIG[selectedLanguage].comingSoon) {
@@ -321,22 +321,35 @@ async function installIndividualAgent(agentName, targetDir, options) {
321
321
 
322
322
  const agentContent = await response.text();
323
323
 
324
- // Create .claude/agents directory if it doesn't exist
325
- const agentsDir = path.join(targetDir, '.claude', 'agents');
326
- await fs.ensureDir(agentsDir);
324
+ // For agents, they are typically part of templates, so we need to determine
325
+ // the appropriate language/framework and install the complete template
326
+ const language = extractLanguageFromAgent(agentContent, agentName);
327
+ const framework = extractFrameworkFromAgent(agentContent, agentName);
327
328
 
328
- // Write the agent file
329
- const targetFile = path.join(agentsDir, `${agentName}.md`);
330
- await fs.writeFile(targetFile, agentContent, 'utf8');
329
+ console.log(chalk.yellow(`📝 Agent "${agentName}" is part of ${language}/${framework} template`));
330
+ console.log(chalk.blue('🚀 Installing complete template with this agent...'));
331
+
332
+ // Install the template that contains this agent (avoid recursion)
333
+ const setupOptions = {
334
+ ...options,
335
+ language,
336
+ framework,
337
+ yes: true,
338
+ targetDirectory: targetDir,
339
+ agent: null // Remove agent to avoid recursion
340
+ };
341
+ delete setupOptions.agent;
342
+ await createClaudeConfig(setupOptions);
331
343
 
332
344
  console.log(chalk.green(`✅ Agent "${agentName}" installed successfully!`));
333
- console.log(chalk.cyan(`📁 Installed to: ${path.relative(targetDir, targetFile)}`));
334
345
  console.log(chalk.cyan(`📦 Downloaded from: ${githubUrl}`));
335
346
 
336
347
  // Track successful agent installation
337
348
  trackingService.trackDownload('agent', agentName, {
338
- installation_type: 'individual_component',
339
- target_directory: path.relative(process.cwd(), targetDir),
349
+ language: language,
350
+ framework: framework,
351
+ installation_type: 'individual_agent',
352
+ template_installed: true,
340
353
  source: 'github_main'
341
354
  });
342
355