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.
- package/bin/create-claude-config.js +2 -3
- package/components/agents/api-security-audit.md +92 -0
- package/components/agents/database-optimization.md +94 -0
- package/components/agents/react-performance-optimization.md +64 -0
- package/components/commands/check-file.md +53 -0
- package/components/commands/generate-tests.md +68 -0
- package/components/mcps/deepgraph-nextjs.json +12 -0
- package/components/mcps/deepgraph-react.json +12 -0
- package/components/mcps/deepgraph-typescript.json +12 -0
- package/components/mcps/deepgraph-vue.json +12 -0
- package/components/mcps/filesystem-access.json +12 -0
- package/components/mcps/github-integration.json +11 -0
- package/components/mcps/memory-integration.json +8 -0
- package/components/mcps/mysql-integration.json +11 -0
- package/components/mcps/postgresql-integration.json +11 -0
- package/components/mcps/web-fetch.json +8 -0
- package/package.json +2 -1
- package/src/file-operations.js +81 -217
- package/src/index.js +24 -11
|
@@ -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
|
|
47
|
-
.option('-f, --framework <framework>', 'specify framework
|
|
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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.
|
|
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": {
|
package/src/file-operations.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
//
|
|
272
|
-
const frameworkFiles = await
|
|
273
|
-
for (const
|
|
274
|
-
const
|
|
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 ${
|
|
134
|
+
console.log(chalk.blue(`⏭️ Skipped ${frameworkFile} (already exists)`));
|
|
279
135
|
continue;
|
|
280
136
|
}
|
|
281
137
|
|
|
282
|
-
await fs.
|
|
138
|
+
await fs.copy(srcFile, destFile, { overwrite: shouldOverwrite });
|
|
283
139
|
}
|
|
284
140
|
|
|
285
|
-
console.log(chalk.green(`✓
|
|
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 -
|
|
288
|
-
await fs.
|
|
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
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const destFile = path.join(
|
|
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 ${
|
|
170
|
+
console.log(chalk.blue(`⏭️ Skipped ${baseCommand} (already exists)`));
|
|
302
171
|
continue;
|
|
303
172
|
}
|
|
304
173
|
|
|
305
|
-
await fs.
|
|
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(`✓
|
|
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
|
|
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
|
|
353
|
-
console.log(chalk.green(`✓
|
|
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
|
|
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
|
|
365
|
-
console.log(chalk.green(`✓
|
|
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
|
-
//
|
|
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
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
|
179
|
-
const selectedLanguage = options.
|
|
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
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
339
|
-
|
|
349
|
+
language: language,
|
|
350
|
+
framework: framework,
|
|
351
|
+
installation_type: 'individual_agent',
|
|
352
|
+
template_installed: true,
|
|
340
353
|
source: 'github_main'
|
|
341
354
|
});
|
|
342
355
|
|